Skip to content
Free public beta until December 4, 2026: every course is open, no card needed. After that, the first chapter of each course stays free and full access is a one-time $39 ($19 for up to 100 founding members chosen for helpful feedback). Your progress is kept. How the beta works

Recipe

Layer a command-line tool's settings

Use when: one setting can come from a built-in default, a config file, an environment variable and a flag

Goal: one merged value per setting, where the most specific source that said something wins

Taught in Configuration

  1. 1

    Give the clap field no default (Option<T>), and read each file key into an Option<T> too.

    Example

    #[arg(short = 'n', long, env = "TALLY_TOP")] top: Option<usize>

    Why: None is how a layer says "I have no opinion"; a default in clap would hide that.

  2. 2

    Put env = "NAME" on the field, with clap's env feature on.

    Why: clap already applies flag-over-variable, and reports a bad value like a bad flag.

  3. 3

    A missing file gives all-None settings; a broken file is an error with its path.

    Why: most users never write the file, but a typo in one must not be ignored.

  4. 4

    cli.x.or(file.x).unwrap_or(DEFAULT) for each setting.

    Why: or keeps the first Some, so the most specific layer that spoke wins.

  5. 5

    Write it in the doc comment, [default: 10].

    Why: clap can't show a default it doesn't know about.

Common mistakes

  • Keeping default_value_t on a field the file is meant to override.
  • Ignoring a config file that fails to parse.
  • Letting the file override a flag the user just typed.