Where Does Configuration Come From?
A robust tool often needs configuration beyond what users type on the command line: API keys, default regions, timeout values, log levels. Users should be able to set these in multiple ways depending on their context — a developer might set a default in a config file, while a CI/CD pipeline sets it via an environment variable, and an operator overrides it at runtime with a flag.
The standard hierarchy of precedence, from lowest priority to highest, is:
1. Default Values (hardcoded in the application)
2. Configuration File (~/.mytool/config.yaml or /etc/mytool/config.yaml)
3. Environment Variables (MYTOOL_TIMEOUT=120)
4. Command Line Flags (--timeout=10)
The Rule: Flags always win. If a user explicitly types --timeout=10, they don't care what the config file says. Environment variables override config files because they represent the deployment environment's intent. Config files override defaults because the user has explicitly chosen a preference.
This hierarchy follows the 12-Factor App methodology (Factor III: Config), which states that configuration that varies between deployments should be stored in environment variables. This makes your tool portable across environments without modifying files.
Practical Implementation:
import os
import argparse
# 1. Start with defaults
config = {"timeout": 30, "region": "us-east-1"}
# 2. Override with environment variables
if os.environ.get("MYTOOL_TIMEOUT"):
config["timeout"] = int(os.environ["MYTOOL_TIMEOUT"])
if os.environ.get("MYTOOL_REGION"):
config["region"] = os.environ["MYTOOL_REGION"]
# 3. Override with CLI flags (highest priority)
parser = argparse.ArgumentParser()
parser.add_argument("--timeout", type=int, default=None)
parser.add_argument("--region", default=None)
args = parser.parse_args()
if args.timeout is not None:
config["timeout"] = args.timeout
if args.region is not None:
config["region"] = args.region
A senior engineer also considers where to document this hierarchy. The --help output should mention which environment variables the tool respects, so users don't have to read source code to discover them.