12-Factor App Config: Best Practices for Environment Variables
The twelve-factor app methodology says "store config in the environment." Here is what that actually means, common mistakes to avoid, and how to implement it properly.
The twelve-factor app methodology has become the standard playbook for building modern, cloud-native applications. Published by Heroku co-founder Adam Wiggins, it defines twelve principles for building software-as-a-service applications that are portable, scalable, and maintainable.
Factor III — "Store config in the environment" — is one of the most cited and most misunderstood. Developers know they should use environment variables. But the details of how to manage them at scale, across teams, and across environments is where things break down.
What Factor III Actually Says
The core principle is simple: anything that varies between deploys (staging, production, developer workstations) should be stored in environment variables, not in code.
This includes:
- •Database connection strings
- •API keys and secrets
- •Feature flags
- •External service URLs
- •Credentials for third-party services
- •Environment-specific settings (debug mode, log level)
The reasoning is straightforward. Code should be identical across all environments. The only thing that changes between your laptop and production is configuration. If that configuration lives in environment variables, you can deploy the same code everywhere and let the environment handle the differences.
What Factor III Does NOT Say
The twelve-factor methodology does not say "put everything in environment variables and call it done." There are important nuances:
It Does Not Say .env Files Are Enough
A .env file is a convenient way to set environment variables locally. But a .env file sitting on a developer's laptop is not a managed configuration system. It does not handle:
- •Sharing secrets securely between team members
- •Tracking who has access to which secrets
- •Synchronizing changes across the team
- •Auditing access for compliance
- •Rotating credentials safely
The .env file is a local convenience tool. It is not a production strategy.
It Does Not Say Secrets Belong in CI/CD Config
Many teams store secrets in their CI/CD platform (GitHub Actions secrets, GitLab CI variables, Vercel environment settings). This works for deployment but creates a fragmented system: some secrets are in GitHub, some are in Vercel, some are in AWS, and nobody has a complete picture.
It Does Not Address the Team Problem
The original twelve-factor guidance was written for small teams where everyone knew everything. In a team of 20 developers across multiple services, "store config in the environment" leaves a lot of questions unanswered. Who can see production secrets? How do you onboard a new developer without pasting secrets in Slack? How do you revoke access when someone leaves?
Common Mistakes
Mistake 1: Hardcoded Defaults That Leak Into Production
// Dangerous pattern
const dbHost = process.env.DB_HOST || "localhost";
If DB_HOST is accidentally unset in production, your application silently connects to localhost instead of failing loudly. This can cause data to be written to the wrong place or, worse, appear to work while silently losing data.
const dbHost = process.env.DB_HOST;
if (!dbHost) {
throw new Error("DB_HOST environment variable is required");
}
Mistake 2: Treating All Config as Equally Sensitive
Not all environment variables are secrets. NODE_ENV=production is configuration but not sensitive. STRIPE_SECRET_KEY is both. Treating them identically leads to either over-engineering (encrypting non-sensitive config) or under-protecting (managing secrets with the same casual approach as non-sensitive settings).
Mistake 3: No Rotation Strategy
API keys and database passwords should be rotated regularly. But if rotating a credential requires updating it in 5 different places (CI/CD, .env files on 10 developer machines, Vercel dashboard, Docker configs), it never happens.
Mistake 4: Secrets Sprawl
Over time, secrets accumulate in unexpected places: old Slack messages, stale CI/CD configs, abandoned staging environments, developer laptops that were never cleaned up. GitGuardian's 2024 report found over 12 million new secrets exposed across public and private repositories.
Better approach: Centralize secrets in one system and regularly audit what exists, who has access, and whether old credentials have been revoked.Implementing Factor III Properly
Here is a practical implementation that stays true to the twelve-factor principle while addressing real-world team needs:
1. Use a .env.example File for Documentation
Commit a .env.example file with all variable names and placeholder values. This documents what your application needs without exposing real values.
2. Validate at Startup
Check that all required environment variables exist before the application starts. Fail immediately and clearly if anything is missing.
3. Centralize Secrets Management
Use a dedicated tool to manage secrets. For small teams, ConfigShield provides a .env-native workflow: import your file, invite your team, and everyone pulls via CLI. For enterprise teams, HashiCorp Vault or AWS Secrets Manager provides dynamic secrets and more granular access control.
4. Separate Config from Secrets
Non-sensitive configuration (port numbers, feature flags, log levels) can live in config files or CI/CD settings. Actual secrets (API keys, database passwords, encryption keys) should live in an encrypted secrets manager.
5. Automate Rotation
Design your deployment pipeline so that rotating a secret requires changing it in exactly one place. The next deploy should pick up the new value automatically.
The Twelve-Factor Config Checklist
- •All environment-specific config is in environment variables
- •No secrets in code, git history, or config files
- •A
.env.examplefile documents all required variables - •Startup validation catches missing variables immediately
- •Secrets are stored in an encrypted, access-controlled system
- •Team members can access secrets without Slack or email
- •Access is revocable when team members leave
- •Rotation is a single-step process
If your team checks all these boxes, you are implementing Factor III the way it was intended. If not, the gap between where you are and where you need to be is usually smaller than you think.
Start managing config the twelve-factor way with ConfigShield →Secure Your Secrets Today
Free forever for solo developers. Bank-grade encryption, audit trails, and CLI access in 30 seconds.