rust-config-tree
rust-config-tree provides configuration-tree loading and CLI helpers for Rust
applications that use layered config files.
Project manual: https://developerworks.github.io/rust-config-tree/. English and Chinese manuals are published as independent mdBook sites with language switch links.
It handles:
- loading a
confiqueschema into a directly usable config object through Figment runtime providers config-template,completions, andinstall-completionscommand handlers- Draft 7 JSON Schema generation for editor completion and validation
- config template generation for YAML, TOML, JSON, and JSON5
- schema directives for TOML and YAML templates without adding runtime fields
- recursive include traversal
.envloading before environment values are merged- source tracking through Figment metadata
- TRACE-level source tracking logs through
tracing - relative include paths resolved from the file declaring them
- lexical path normalization
- include cycle detection
- deterministic traversal order
- mirrored template target collection
- automatic YAML template splitting for nested schema sections
Applications provide their schema by deriving confique::Config and
implementing ConfigSchema to expose the schema's include field.
Install
[]
= "0.1"
= { = "0.4", = ["yaml", "toml", "json5"] }
= { = "0.10", = ["yaml", "env"] }
= { = "1", = ["derive"] }
= { = "1", = ["derive"] }
= { = "4", = ["derive"] }
Configuration Schema
Your application schema owns the include field. rust-config-tree only needs a
small adapter that extracts includes from the intermediate confique layer.
use PathBuf;
use Config;
use ConfigSchema;
Relative include paths are resolved from the file that declares them:
# config.yaml
include:
- config/server.yaml
mode: shadow
# config/server.yaml
server:
port: 7777
Load the final schema with load_config:
use load_config;
load_config loads the first .env file found by walking upward from the root
config file's directory before asking Figment to read schema-declared
environment variables. Values already present in the process environment are
preserved and take precedence over .env values.
Runtime config loading is performed through Figment. confique remains
responsible for schema metadata, defaults, validation, and template generation.
Environment variable names are read from #[config(env = "...")]; the loader
does not use Env::split("_") or Env::split("__"), so a variable such as
APP_DATABASE_POOL_SIZE can map to a field named database.pool_size.
load_config does not read command-line arguments because CLI flags are
application-specific. Add CLI overrides by merging a provider after
build_config_figment, then validate with load_config_from_figment:
CLI flag names are not derived from config paths. Use normal application flags
such as --server-port or --database-url; do not rely on --server.port or
a.b.c unless the application deliberately implements that parser. The nested
serialized override shape decides which config key is overridden.
Only values represented in the application's CliOverrides provider can
override configuration. This is intended for frequently adjusted runtime
parameters, where changing a flag for one run is better than editing a config
file. Keep stable configuration in files and expose only deliberate temporary
overrides as CLI flags.
use Serialized;
use Serialize;
use ;
With CLI overrides merged this way, runtime precedence is:
command-line overrides
> environment variables
> config files
> confique code defaults
Use load_config_with_figment when the caller needs source metadata:
use load_config_with_figment;
The loader also emits config source tracking with tracing::trace!. Those
events are produced only when TRACE is enabled by the application's tracing
subscriber. If tracing is initialized after config loading, call
trace_config_sources::<AppConfig>(&figment) after installing the subscriber.
Template Generation
Templates are rendered with the same schema and include traversal rules. The output format is inferred from the output path:
.yamland.ymlgenerate YAML.tomlgenerates TOML.jsonand.json5generate JSON5-compatible templates- unknown or missing extensions generate YAML
Use write_config_schema to create one Draft 7 JSON Schema that can be shared
by TOML, YAML, and JSON configuration files:
use write_config_schema;
Use write_config_templates to create a root template and every template file
reachable from its include tree:
use write_config_templates;
Use write_config_templates_with_schema when generated TOML and YAML templates
should bind that schema for IDE completion and validation:
use write_config_templates_with_schema;
TOML targets receive #:schema ./schemas/myapp.schema.json. YAML targets
receive # yaml-language-server: $schema=./schemas/myapp.schema.json. JSON and
JSON5 targets intentionally do not receive a $schema field; bind them with
editor settings such as VS Code json.schemas.
Template generation chooses its source tree in this order:
- an existing config path
- an existing output template path
- the output path, treated as a new empty template tree
If a source node has no include list, rust-config-tree derives child template
files from nested confique sections. With the schema above, an empty
config.example.yaml source produces:
config.example.yaml
config/server.yaml
The root template receives an include block for config/server.yaml. YAML
targets that map to a nested section, such as config/server.yaml, contain only
that section. Further nested sections are split recursively in the same way.
Override template_path_for_section when a section should be generated at a
different path:
use PathBuf;
use Config;
use ConfigSchema;
The default section path is config/<section>.yaml for top-level nested
sections. Nested children are placed under their parent file stem, for example
config/trading/risk.yaml.
CLI Integration
Flatten ConfigCommand into your existing clap command enum to add:
config-templateconfig-schemacompletionsinstall-completions
The consuming application keeps its own Parser type and its own command enum.
rust-config-tree only contributes reusable subcommands:
- Add
#[command(subcommand)] command: Commandto the application's parser. - Add
#[command(flatten)] Config(ConfigCommand)to the application'sSubcommandenum. - Clap expands the flattened variants into the same subcommand level as the application's own commands.
- Match that variant and call
handle_config_command::<Cli, AppConfig>.
Application-specific config override flags stay on the application's own parser.
For example, --server-port can map to server.port by building a nested
CliOverrides { server: Some(CliServerOverrides { port }) } value and merging
it with Serialized::defaults.
use PathBuf;
use ;
use Config;
use JsonSchema;
use ;
config-template --output <path> writes templates to the selected path. If no
output path is provided, it writes config.example.yaml in the current
directory. Add --schema <path> to bind TOML and YAML templates to a generated
JSON Schema without adding a runtime $schema field.
config-schema --output <path> writes a Draft 7 JSON Schema. If no output path
is provided, it writes schemas/config.schema.json.
completions <shell> prints completions to stdout.
install-completions <shell> writes completions under the user's home
directory and updates the shell startup file when the shell requires it. Bash,
Elvish, Fish, PowerShell, and Zsh are supported.
Lower-Level Tree API
Use load_config_tree when you do not use confique or when you need direct
access to traversal results:
use ;
use ;
The tree API normalizes paths lexically, rejects empty include paths, detects recursive include cycles, and skips files that were already loaded through another include branch.
License
Licensed under either of:
- Apache License, Version 2.0
- MIT license
at your option.