← Recipes

阅读中文版本

Implement CLI Config Precedence

Define a clear precedence of flags over environment over config file over defaults so behaviour is predictable.

~30 mincliconfigurationjavascript

Task

Merge CLI flags, environment variables, a config file, and defaults in a documented order.

When to use this

Users are confused because an environment variable silently overrides their command-line flag.

Prerequisites

  • A CLI with settings
  • A config file format
  • Environment variable conventions

Steps

1. Merge sources in a fixed precedence order.

const config = {
  ...defaults,
  ...readConfigFile(path),
  ...pickEnv(process.env),
  ...pickFlags(argv),
};

Expected output: Flags win over environment, which wins over the file, which wins over defaults.

2. Document and test the order.

test('flag beats env', () => {
  expect(resolve({ FLAG: 'a' }, { FLAG: 'b' })).toBe('a');
});

Expected output: A test locks the precedence so refactors cannot silently change it.

Troubleshooting

Problem

Empty values override unintentionally

Solution

Treat empty strings as unset unless explicitly meaningful.

Problem

Config file not found

Solution

Fall back to defaults with a warning rather than failing hard.

Limitations

  • Precedence must be documented for users.
  • Complex merging of nested structures needs care.
  • Does not cover secret storage.

What this recipe does

Merge CLI flags, environment variables, a config file, and defaults in a documented order.

Users are confused because an environment variable silently overrides their command-line flag.

Prerequisites

  • A CLI with settings
  • A config file format
  • Environment variable conventions

Procedure

  1. Merge sources in a fixed precedence order.
const config = {
  ...defaults,
  ...readConfigFile(path),
  ...pickEnv(process.env),
  ...pickFlags(argv),
};

Expected result: Flags win over environment, which wins over the file, which wins over defaults.

  1. Document and test the order.
test('flag beats env', () => {
  expect(resolve({ FLAG: 'a' }, { FLAG: 'b' })).toBe('a');
});

Expected result: A test locks the precedence so refactors cannot silently change it.

How to confirm it worked

Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows with all sources set, the flag value wins, and a test enforces the documented order.

Troubleshooting

Empty values override unintentionally — Treat empty strings as unset unless explicitly meaningful.

Config file not found — Fall back to defaults with a warning rather than failing hard.

Limitations

  • Precedence must be documented for users.
  • Complex merging of nested structures needs care.
  • Does not cover secret storage.