Quick Start
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Add the crate and the schema/runtime libraries used by your application:
[dependencies]
rust-config-tree = "0.2"
confique = { version = "0.4", features = ["yaml", "toml", "json5"] }
figment = { version = "0.10", features = ["yaml", "toml", "json", "env"] }
schemars = { version = "1", features = ["derive"] }
serde = { version = "1", features = ["derive"] }
clap = { version = "4", features = ["derive"] }
Define a confique schema and implement ConfigSchema for the root type:
#![allow(unused)]
fn main() {
use std::path::PathBuf;
use confique::Config;
use rust_config_tree::ConfigSchema;
#[derive(Debug, Config)]
struct AppConfig {
#[config(default = [])]
include: Vec<PathBuf>,
#[config(nested)]
server: ServerConfig,
}
#[derive(Debug, Config)]
struct ServerConfig {
#[config(default = "127.0.0.1")]
#[config(env = "APP_SERVER_BIND")]
bind: String,
#[config(default = 8080)]
#[config(env = "APP_SERVER_PORT")]
port: u16,
}
impl ConfigSchema for AppConfig {
fn include_paths(layer: &<Self as Config>::Layer) -> Vec<PathBuf> {
layer.include.clone().unwrap_or_default()
}
}
}
Load the config:
#![allow(unused)]
fn main() {
use rust_config_tree::load_config;
let config = load_config::<AppConfig>("config.yaml")?;
println!("{config:#?}");
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Use a root file with recursive includes:
# config.yaml
include:
- config/server.yaml
# config/server.yaml
server:
bind: 0.0.0.0
port: 3000
The default load_config precedence is:
environment variables
> config files, with later merged files overriding earlier files
> confique code defaults
When includes are loaded by the high-level API, the root file has the highest file priority. Included files provide lower-priority values and can be used for defaults or section-specific files.
Command-line arguments are application-specific, so load_config does not read
them automatically. Use the ConfigOverrides derive macro to build an override
provider from parsed CLI flags:
#![allow(unused)]
fn main() {
use clap::Parser;
use rust_config_tree::{
ConfigSchema,
cli::ConfigOverrides,
config::{build_config_figment, load_config_from_figment},
};
#[derive(Debug, Parser, ConfigOverrides)]
struct Cli {
/// Config file path
#[arg(long)]
config: Option<std::path::PathBuf>,
/// Override server port
#[arg(long)]
#[config_override(path = "server.port")]
server_port: Option<u16>,
/// Override log level
#[arg(long)]
#[config_override(path = "log.level")]
log_level: Option<String>,
}
let cli = Cli::parse();
let figment = build_config_figment::<AppConfig>("config.yaml")?
.merge(cli.config_overrides()?);
let config = load_config_from_figment::<AppConfig>(&figment)?;
let _ = config;
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
The #[config_override(path = "...")] attribute maps each CLI flag to a dotted
config path. Only provided flags produce override values; omitted flags
disappear. The override provider is merged last, so provided flags override file
and environment values:
command-line overrides
> environment variables
> config files
> confique code defaults