In the twelve-factor method, config is everything likely to vary between deploys: database handles, credentials for outside services, and per-deploy values such as the hostname. It lives outside the code, usually in environment variables. Internal wiring that never changes between deploys, like routes, is code, not config.
The definition in plain words
The twelve-factor text defines config as everything that is likely to vary between deploys, meaning staging, production and developer machines. Its examples include resource handles to databases and other backing services, credentials for external services, and values such as the canonical hostname of the deploy.
Application wiring is different. The same source says internal wiring such as routes stays the same across deploys, so it is not config. A route table belongs in code because every environment runs the same one.
The litmus test
The source gives a simple test. Could you open source the codebase at any moment without exposing a credential? If yes, config is separated from code properly. If no, something sensitive is living in the repository.
This test is useful because it is binary. It does not ask whether you have a secrets tool or a policy document. It asks what a stranger would see in a clone of your repository today.
What strict separation rules out
The source says config varies a great deal across deploys and code does not. That rules out hardcoded constants, and it also rules out config files checked into version control. It even criticizes files that are kept out of the repository by convention, because they are easy to commit by mistake and tend to scatter across the project in different formats.
Why environment variables
The method stores config in environment variables for three stated reasons. They are easy to change between deploys without touching code. They are unlikely to be checked in by accident. And they are a standard that does not depend on a language or operating system.
Be aware that the security community has since added caveats about holding secrets specifically in environment variables. We cover those in where environment variables leak secrets. The separation principle still stands. The storage choice for the most sensitive values is a separate decision.
Avoid named environment bundles
The twelve-factor text warns against grouping config into named environments such as development, test and production. That scales badly: every new deploy type adds a name, and each developer setup can create more combinations. The recommendation is to treat each variable as a granular control, managed independently for each deploy.
In practice, one smell is code that branches on an environment name to pick a database. Prefer a variable that holds the database address and nothing else.
A short audit
- Search the repository for passwords, tokens and hostnames, including in history.
- List every value that differs between your environments, then confirm each one comes from outside the code.
- Check that a new environment needs only new values, never a code change.
If you want a quick automated look at the dependency side of the same repository, Safeguard offers a free scan at gold.safeguard.sh/scan.
Quick check
Is a feature flag config?
Often yes. A flag that differs per deploy is config in the twelve-factor sense, and it should come from outside the code. We discuss flags in feature flags are production config.
Sources
Last reviewed: 19 October 2026.