Implement CLI Config Precedence
Define a clear precedence of flags over environment over config file over defaults so behaviour is predictable.
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
- 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.
- 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.