aiwg
Version:
Deployment tool and support utility for AI context. Copies agents, skills, commands, rules, and behaviors into the paths each AI platform reads (Claude Code, Codex, Copilot, Cursor, Warp, OpenClaw, and 6 more) so one source of truth works across 10 platfo
61 lines (45 loc) • 3.1 kB
Markdown
---
name: config-in-environment
severity: MEDIUM
category: configuration
factor: 12-factor-III
---
# Config in the Environment
## Rule
Configuration values that differ between deployment environments (dev, staging, production) must be stored in environment variables, not in source code or checked-in config files.
**Why:** Configuration that varies between environments is by definition environment-specific. Storing it in code produces one of three bad outcomes: (1) env-specific branches in source, (2) separate builds per environment (violates Factor V build/run separation), or (3) secrets accidentally committed.
**How to apply:**
### What belongs in environment variables
- Backing service URLs (database, cache, queue, external APIs)
- Credentials and tokens (already covered by `token-security.md`)
- Feature flags that differ per environment
- Resource limits (thread pool size, connection pool size)
- Log level and observability endpoints
- Environment identity itself (`APP_ENV=production`)
### What does NOT belong in environment variables
- Business logic constants (tax rates, timeout constants that never differ per env)
- Code structure decisions (these are source code)
- Configuration-as-code for infrastructure (Terraform, Pulumi) — that's a separate concern
### How to consume
- Read env vars at startup (fail-fast if required vars missing)
- Validate types and ranges (URL is parseable, port is a number, etc.)
- Provide a `.env.example` file at project root documenting every env var used
- Use a config object/struct that centralizes all env reads (no scattered `os.getenv` calls)
### Secrets within config
- Follow `rules/token-security.md` — secrets load from secret managers or files referenced by env vars, not directly from env
- Example: `DATABASE_URL_FILE=/run/secrets/db_url` rather than `DATABASE_URL=postgres://...` in the orchestrator
## What to check
1. **`.env.example` exists at project root** and lists every env var the application reads
2. **No hardcoded URLs, hostnames, or ports** in source files (exception: defaults for local dev marked as such)
3. **No per-environment branches** like `if APP_ENV == "production"` scattered in business logic (use the config object instead)
4. **Config validation at startup** — app fails fast if required env vars are missing or malformed
5. **Documentation**: every env var has a description in `.env.example` or `deployment-environment-template.md`
## Acceptable deviations (require ADR)
- **Library defaults for optional settings** — hardcoding a reasonable default is fine; document why in code
- **Build-time configuration** (feature compile flags for native binaries) — different mechanism, justify why env vars won't work
- **Legacy code being migrated** — temporary, with explicit remediation plan
## Related
- Factor III (config) — https://12factor.net/config
- `rules/token-security.md` — secrets handling (covers the subset that are credentials)
- `rules/stateless-processes.md` — processes depend on env config to be interchangeable
- Issue #821 — 12-factor gap analysis