Part 0 · 2 chapters · ~12 min
The Twelve-Factor Baseline and Its Limits
What twelve-factor got right about config in the environment, strict separation of config from code, why .env files leak, and the points where environment variables stop working: structure, change history, secrets, dynamic change and per-tenant variation.
1
Config in the environment, and where it breaks
The twelve-factor rule is store config in the environment, separate from code: the same build artifact runs in every environment, and nothing secret lives in the repository. It is still the right baseline.
| where env vars stop working | symptom | next step |
|---|---|---|
| structure | JSON blobs in a variable, 80 variables per service | typed config files plus a schema |
| change history | "who changed RATE_LIMIT and when?" | config in Git, or a config service with audit |
| secrets | printed in crash dumps, visible in /proc/<pid>/environ, copied into CI logs, sitting in .env files on laptops | a secrets manager, injected at runtime, short-lived |
| dynamic change | a restart for every change | remote config or flags with safe reloads |
| per-tenant variation | if statements per country | tenant config as data (Platform course) |
code
// load and validate config once at startup: fail fast, with a clear message
import { z } from 'zod';
const Config = z.object({
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url(),
TRANSFER_LIMIT_KOBO: z.coerce.number().int().positive().default(20_000_000),
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});
export const config = Config.parse(process.env); // throws at boot, not at 3 a.m. on first use2
Configuration layers and precedence
Real services merge several layers. The bugs come from not knowing which layer set a value, and from layers that change without review.
CONFIGURATION LAYERS
later layers override earlier ones; know which layer a value came from
swipe the figure sideways, or tap expand for full screen
1/6
defaults
Every setting has a safe default in code, so a missing value never crashes the service or, worse, enables something dangerous.
safe defaults in codemissing config should be boring