dynamic-config 0.1.0

Hot-reloadable, lock-free application configuration with a one-attribute API, built on figment.
Documentation

dynamic-config

Hot-reloadable, layered configuration for Rust — one attribute, lock-free reads.

CI Security crates.io docs.rs MSRV License: MIT OpenSSF Scorecard

The Book · API docs · Examples · Changelog


Configuration that stays live after startup: files, environment, remote stores and command-line flags merged into one typed struct, re-read when they change, served to every thread as one atomic load.

[dependencies]
dynamic-config = { version = "0.1.0", features = ["toml", "watch"] }
use dynamic_config::dynamic_config;
use serde::Deserialize;

#[dynamic_config(
    files = ["config.toml", "secrets.json"],
    key   = "db",
    env   = "APP_",
    watch,
)]
#[derive(Debug, Deserialize)]
pub struct DatabaseConfig {
    pub host: String,
    pub port: u16,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    DatabaseConfig::init()?;                  // load once, fail fast on a bad config
    DatabaseConfig::start_watch()?.detach();  // reload in the background from now on

    let config = DatabaseConfig::current();   // one atomic load, on any thread
    println!("{}:{}", config.host, config.port);

    Ok(())
}

Why this one

  • Reads are lock-free. current() is an atomic pointer load — ~17 ns — so configuration can be read per request without a second thought.
  • A bad edit cannot take the process down. A file that no longer parses or validates degrades to "no change"; the previous snapshot keeps serving, and the error is reported.
  • Layers with provenance. defaults < discovered < files < remote < .env < environment < bindings < flags < overrides — and source_of("key") names the file, variable or store a value actually came from.
  • Secrets stay out of diagnostics. Errors, diffs, reports and {:?} print paths and types, never values — enforced by its own test suite.
  • Any runtime, or none. The async surface is a Future and a thread; tokio, smol and Embassy all drive it. Blocking work never lands on your executor.
  • Remote stores are explicit. refresh_remote() does the network round trip; load() never does. Seven store crates ship, each watching the way its protocol allows.

The full story — precedence, profiles, discovery, hot reload, encryption, schema export, units, the last-known-good cache, testing patterns — lives in the book.

The workspace

Crate What Stability
dynamic-config the engine: loading, layers, storage, watching Beta
dynamic-config-macros #[dynamic_config] Beta
dynamic-config-etcd etcd, push watch over gRPC Experimental
dynamic-config-consul Consul KV, blocking queries Experimental
dynamic-config-nats NATS JetStream KV, push watch Experimental
dynamic-config-redis Redis, keyspace notifications Experimental
dynamic-config-vault Vault KV v2, version polling Experimental
dynamic-config-s3 S3 & compatibles, ETag polling — needs tokio Experimental
dynamic-config-firestore Firestore REST, updateTime polling Experimental
dynamic-config-embedded the same shape for no_std targets Experimental

Beta: breaking changes bump the minor pre-1.0 and are announced in the changelog. Experimental: may change shape without ceremony — pin an exact version. Details in Stability Tiers.

Every store follows the same contract — the current value is not announced at startup, a deleted key is not a change, transport failures retry, a panicking callback ends the watch with an error — and each documents its stop latency and change-detection rule side by side in Store Crates at a Glance.

MSRV

floor
dynamic-config core 1.71
schema feature 1.74 (schemars)
watch / age / full features 1.85 (measured, not declared)
store crates 1.85 — nats/redis/s3: 1.88 (their clients)
dynamic-config-embedded 1.83

MSRV changes are breaking. Every floor has a CI row against a real toolchain; the full table with reasons is in MSRV & Features.

Contributing

CONTRIBUTING.md is the short version; the onboarding tour walks every module. What will not be built, and why, is in Limitations & Not Planned; what might be is in ROADMAP.md.

License

MIT.