clapfig 0.12.0

Rich, layered configuration for Rust CLI apps
Documentation

clapfig

Rich, layered configuration for Rust applications. Define a struct, point at your files, and go.

clapfig discovers, merges, and manages configuration from multiple sources — config files, environment variables, and programmatic overrides — through a pure Rust builder API. The core library has no dependency on any CLI framework: you can use it in GUI apps, servers, or with any argument parser. For clap users, an optional adapter provides drop-in config gen|list|get|set|unset subcommands with zero boilerplate.

Built on confique for struct-driven defaults and commented template generation.

Features

Core (always available, no CLI framework needed):

  • Struct as source of truth — define settings as a Rust struct with defaults and /// doc comments
  • Layered merge — defaults < config files < env vars < overrides, every layer sparse, customizable precedence order
  • Multi-path file search — platform config dir, home, cwd, ancestor walk, or any path
  • Search modes — merge all found configs or use the first match
  • Ancestor walk — walk up from cwd to find project configs, with configurable boundary (.git, filesystem root)
  • Prefix-based env varsMYAPP__DATABASE__URL maps to database.url automatically
  • Strict mode — unknown keys error with file path, key name, and line number (on by default)
  • Template generation — emit a commented sample config from the struct's doc comments
  • Persistence with named scopes — global/local config file patterns with --scope targeting

Clap adapter (clap feature, on by default):

  • Config subcommand — drop-in config gen|get|set|unset|list for clap
  • --scope flag — target a specific scope for any config subcommand
  • Auto-matching overrides — map clap args to config keys by name in one call

Quick Start

[dependencies]
clapfig = "0.10"

Define your config with confique's Config derive:

use confique::Config;
use serde::{Serialize, Deserialize};

#[derive(Config, Serialize, Deserialize, Debug)]
pub struct AppConfig {
    /// The host address to bind to.
    #[config(default = "127.0.0.1")]
    pub host: String,

    /// The port number.
    #[config(default = 8080)]
    pub port: u16,

    /// Database settings.
    #[config(nested)]
    pub database: DbConfig,
}

#[derive(Config, Serialize, Deserialize, Debug)]
pub struct DbConfig {
    /// Connection string URL.
    pub url: Option<String>,

    /// Connection pool size.
    #[config(default = 10)]
    pub pool_size: usize,
}

Load it:

use clapfig::Clapfig;

fn main() -> anyhow::Result<()> {
    let config: AppConfig = Clapfig::builder()
        .app_name("myapp")
        .load()?;

    println!("Listening on {}:{}", config.host, config.port);
    Ok(())
}

That app_name("myapp") call sets sensible defaults:

  • Searches for myapp.toml in the platform config directory
  • Merges env vars prefixed with MYAPP__
  • Fills in #[config(default)] values for anything not provided

Without clap:

clapfig = { version = "0.10", default-features = false }

Layer Precedence

Compiled defaults     #[config(default = ...)]
       ↑ overridden by
Config files          search paths in order, later paths win
       ↑ overridden by
Environment vars      MYAPP__KEY
       ↑ overridden by
URL query params      .url_query()          (requires "url" feature)
       ↑ overridden by
Overrides             .cli_override()

Every layer is sparse. You only specify the keys you want to override. Unset keys fall through to the next layer down.

This is the default order. You can customize it with .layer_order():

use clapfig::{Clapfig, Layer};

let config: AppConfig = Clapfig::builder()
    .app_name("myapp")
    .layer_order(vec![Layer::Env, Layer::Files, Layer::Cli])
    .load()?;

Layers listed later override earlier ones. Omitting a layer excludes it from merging entirely. See Layer for the available variants.

Demo

The repo includes a runnable example that exercises every feature:

cargo run --example clapfig_demo -- echo
cargo run --example clapfig_demo -- --color blue --port 8080 echo
cargo run --example clapfig_demo -- config gen
cargo run --example clapfig_demo -- config list
cargo run --example clapfig_demo -- config get server.port

See examples/clapfig_demo/ for the full source.

Documentation

The full guide — design rationale, search paths and modes, environment variables, programmatic overrides, persistence, clap adapter, template generation, strict mode, and normalizing values — lives in the crate-level docs on docs.rs.