Most production incidents I’ve debugged came down to configuration. A missing environment variable. A wrong database URL. A feature flag stuck in the wrong state. Code was fine; configuration was the problem.
Configuration management is the unsexy work that prevents those 3 AM pages.
The Core Principles
1. Separate Configuration from Code
Configuration should never be baked into your application binary or container image.
Wrong:
| |
Also wrong:
| |
Right:
| |
| |
Why? The same image should run in dev, staging, and production. Only configuration differs.
2. Validate Configuration at Startup
Fail fast if configuration is missing or invalid:
| |
A clear error at startup beats a cryptic error at 3 AM when that code path finally runs.
3. Make Configuration Explicit
Document every configuration option:
| |
If it’s not documented, someone will misconfigure it.
4. Use Hierarchical Configuration
Configuration should layer: defaults → environment-specific → instance-specific → overrides.
| |
This lets you have sensible defaults while allowing specific overrides.
5. Version Your Configuration
Configuration changes should be tracked like code changes:
For secrets, use a separate system (Vault, AWS Secrets Manager) and reference them:
| |
Common Patterns
Environment Variables
The twelve-factor standard. Simple, universal, works everywhere.
| |
Pros:
- Works in any language
- Easy to inject in containers, CI, etc.
- No files to manage
Cons:
- No structure (everything is a string)
- Hard to see “all configuration” at once
- Can leak in logs, process listings
Best for: Simple applications, container deployments, cloud-native environments.
Configuration Files
YAML, JSON, TOML, INI — structured configuration in files.
| |
Pros:
- Structured, supports nesting
- Easy to read and edit
- Can be templated
Cons:
- Files need to be deployed
- Requires parsing logic
- Format choice can be contentious (YAML vs TOML debates)
Best for: Complex configuration, local development, applications with many options.
Remote Configuration
Fetch configuration from a central service (Consul, etcd, AWS Parameter Store).
| |
Pros:
- Centralized management
- Can update without redeployment
- Built-in encryption for secrets
Cons:
- Adds external dependency
- Network latency at startup
- Needs caching strategy
Best for: Microservices, multi-environment deployments, dynamic configuration.
Feature Flags
A special case of configuration: controlling feature rollout.
| |
Feature flag systems (LaunchDarkly, Unleash, Flagsmith) add:
- Percentage rollouts (10% of users see new feature)
- User targeting (beta users, specific accounts)
- A/B testing (track outcomes per variant)
- Kill switches (disable instantly without deploy)
Rule: Feature flags are temporary. Remove them after rollout is complete. Stale flags become technical debt.
Anti-Patterns
Configuration Drift
Environment configurations diverge over time:
- Staging has different settings than production
- One server has an override someone added manually
- Nobody knows the “canonical” configuration
Fix: Infrastructure as Code. Terraform, Ansible, or Kubernetes manifests define the configuration. Drift is detected and corrected automatically.
Secret Sprawl
Secrets copied into:
- Environment files
- CI/CD configurations
- Developer laptops
- Slack messages
Fix: Centralized secret management. Vault, AWS Secrets Manager, or similar. Secrets are fetched at runtime, never stored in files or repositories.
The God Config
One massive configuration object passed everywhere:
| |
Fix: Inject only what’s needed. Use dependency injection or specific configuration objects:
| |
Configuration as Logic
| |
You’ve invented a programming language in YAML. This is hard to test, hard to debug, and hard to reason about.
Fix: Keep logic in code. Use configuration for simple values, not business rules.
Testing Configuration
Validate in CI
| |
Catch typos and missing values before deployment.
Environment Parity
Test with production-like configuration:
| |
If tests pass with different configuration than production, they’re lying to you.
Configuration Diff on Deploy
| |
Make configuration changes visible and intentional.
Configuration is the connective tissue between your code and the environment it runs in. Treat it with the same care you’d give to code: version it, validate it, test it, and document it. Your future self — the one who’s not debugging at 3 AM — will thank you.