Blog Post

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.

|7 min read
12 factor apptwelve factor configenvironment variables best practicesconfig managementcloud native config

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

javascript
// 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.

Better approach: Validate all required environment variables at startup and crash immediately if any are missing.
javascript
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).

Better approach: Classify your variables. Non-sensitive config can live in config files or CI/CD settings. Secrets should live in a dedicated secrets manager with encryption and access control.

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.

Better approach: Use a single source of truth for secrets. Update once, and every environment pulls the latest value automatically on next deploy or restart.

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.example file 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 →
ConfigShield

Secure Your Secrets Today

Free forever for solo developers. Bank-grade encryption, audit trails, and CLI access in 30 seconds.

ConfigShieldStart Free