What is twelve-factor config?
On this page
Twelve-factor config is the third principle of the Twelve-Factor App methodology: everything that changes between deploys of the same code, such as database addresses, credentials and per-environment hostnames, is kept out of the code and supplied to the program through environment variables.
What the principle says
The Twelve-Factor App defines config as "everything that is likely to vary between deploys (staging, production, developer environments, etc)". Its test for whether you have separated config from code is memorable: could the codebase "be made open source at any moment, without compromising any credentials"? If not, there is a hardcoded secret somewhere.
It then picks environment variables as the carrier, because they "are easy to change between deploys without changing any code" and work the same in every language and operating system.
Why teams still follow it
- One build, many deploys. The same artifact runs in staging and production with different values, so what you tested is what you ship.
- No secrets in the repository. Reading
process.env.DATABASE_URLnames a setting without containing it. - Tool independence. A container platform, a systemd unit, a CI job and a developer's shell can all set environment variables.
Where it falls short
The methodology says where config goes, not how values get there safely. Environment variables are visible to the process and anything it starts, can show up in crash reports and debug pages, and are often filled from a .env file that sits on disk and travels by chat. Following the principle with a plaintext file on every laptop meets the letter and misses the point.
It also takes a position many teams don't follow. Grouping settings into named environments such as development, test and production "does not scale cleanly", the text argues; each variable should be "independently managed for each deploy." In practice, most teams group by environment anyway, because access, review and audit are easier to reason about per environment than per variable.
Common mistakes
- Config that changes code paths.
if (env === "production")checks scattered through the code reintroduce the coupling the principle removes. Prefer specific settings such asPAYMENTS_MODE=live. - Build-time config treated as run-time. Variables that a front-end build inlines are fixed in the artifact; see public environment variable.
- Inheriting everything. A program that receives the whole parent environment also receives credentials it was never meant to have.
How Crunu applies it
Crunu delivers config the twelve-factor way, at start time through the process environment, and adds the parts the principle leaves open. crunu run decrypts an environment in memory and starts the program with its variables. By default the program gets only a short allowlist from the parent, such as PATH, HOME and LANG, plus the environment's variables, and never the credentials crunu itself uses:
crunu run --env payments-api/staging -- ./bin/server--inherit-env passes the whole parent environment when you need it. With --restart on-change, a changed value restarts the program with the new variables, so config changes without a new build.
Crunu does group values into deployment environments, unlike the methodology's advice, because each environment is also an encryption key and an access list. You can combine several with repeated --env flags when a deploy needs values from more than one. The team side of this is in how to share .env files with your team.
Sources
- The Twelve-Factor App: III. Config, checked October 30, 2026.
From the blog
Servers
One .env file, four parsers: Node, Python, Docker, systemd
The same .env line can give three different values. We ran one file through Node, dotenv, python-dotenv, Compose and docker run, and read systemd's rules.
Sharing .env files guide
Migration
Exporting secrets from Doppler or Infisical
The CLI commands that turn a Doppler config or an Infisical environment into a .env file, the defaults that change what you get, and what stays behind.
Sharing .env files guide
Practices
Keeping .env.example in sync with every environment
A .env.example drifts because nothing breaks when it's wrong. Compare names, never values, fail CI on missing variables, and compare real environments.
Sharing .env files guide