Async ConfigStack
v0.4.0 adds async operations to ConfigStack. You still build a stack from named DotCfg sources; its file reads and writes then use Tokio when you call the async methods. See the async I/O introduction for feature setup.
use dotcfg::{ConfigStack, DotCfg};
let defaults = DotCfg::new("myapp").at_dir("./config/defaults");
let project = DotCfg::new("myapp").at_dir("./config/project");
let cfg = ConfigStack::new()
.layer("defaults", defaults)
.layer("project", project)
.write_to("project")
.with_env_prefix("APP")
.build()?;
let port: u16 = cfg.get_as_async("server.port").await?;
cfg.set_val_async("server.port", 8080u16).await?;Read the resolved view
get_async() returns a string; get_as_async() returns the type you request. load_async() deserializes the complete resolved view and returns None only when every source is missing and no matching environment value exists. Use load_or_error_async() to require a source.
let config: Option<AppConfig> = cfg.load_async().await?;
let required: AppConfig = cfg.load_or_error_async().await?;
// Writes only the value supplied, to the project source.
cfg.save_async(&required).await?;Earlier files have lower precedence than later files, and environment overrides win over both. Nested maps merge, while arrays and scalar values replace earlier values. The layers and resolution guide explains these rules in detail; the async methods use the same resolution.
Write to the chosen source
set_async(), set_val_async(), and save_async() write only to the source selected by write_to(). save_async() writes the value you pass; it does not copy lower layers or environment values into that file. A stack without a write target returns Error::NoWriteTarget for writes.
Direct source() access returns a DotCfg reference and bypasses stack resolution. For individual keys, see async key access. The ConfigStack reading and writing guide covers source ownership in more detail.