env
The Complete Env Variable Playbook: Best Practices, Security & Deployment
Environment variables — commonly referred to as env — are one of the most fundamental yet misunderstood tools in software development. They bridge the gap between code and infrastructure, enabling seamless configuration across development, staging, and production environments without a single line of code change. This playbook gives you everything you need to manage them like a senior engineer.
Key Takeaways
- Separate config from code: Never hard-code secrets or environment-specific values directly into your application source.
- Use
.envfiles locally, not in production: Production systems should receive env vars through platform-native secret managers, not flat files. - Validate every variable on startup: A missing env var should fail fast, not silently produce incorrect behavior.
- Never commit
.envfiles to version control: Add them to.gitignoreimmediately and use template files (.env.example) instead. - Rotate credentials regularly: Treat env secrets like any other credential — rotate on a schedule and revoke on change.
- Prefix your variables logically: Use consistent naming conventions like
APP_,DB_, orAPI_to avoid collisions.
What Are Environment Variables?
Environment variables are dynamic key-value pairs stored at the OS or platform level. Applications read them at runtime to adjust behavior based on their current environment. They are a core principle of the 12-Factor App methodology, which identifies "Config" as a distinct factor separate from code.
Why They Matter
- Security: Secrets never touch your codebase or repository history.
- Portability: The same Docker image or binary runs identically across dev, CI, staging, and production.
- Operational flexibility: Change behavior without redeploying — restart and reconfigure.
- Auditability: Centralized secret management provides access logs and rotation trails.
Env Management Approaches: Comparison
Choosing the right strategy depends on your stack, team size, and compliance requirements. Here is how the most common approaches compare:
| Approach | Best For | Security Level | Complexity | Cost |
|---|---|---|---|---|
.env local files |
Local development, small projects | Low — stored in plaintext | Low | Free |
| OS-level export | Scripting, CI pipelines | Medium — visible to process listing | Low | Free |
| Container platforms (Docker Swarm, ECS) | Containerized deployments | Medium-High — integrated with IAM | Medium | Included in platform |
| Kubernetes Secrets | K8s-native workloads | High — encrypted at rest, RBAC-scoped | Medium | Free (managed etcd) |
| Dedicated secret managers (AWS Secrets Manager, HashiCorp Vault) | Enterprise, regulated environments | Very High — audit trails, rotation, KMS-encrypted | High | Paid per secret |
| CI/CD secret stores (GitHub Actions, GitLab CI) | Automated pipeline config | High — scoped to repository | Low-Medium | Free tier included |
Env Variable Naming Conventions
Consistent naming prevents collisions and makes your configuration instantly readable. Follow these rules:
- UPPERCASE_WITH_UNDERSCORES — the universal standard across all platforms.
- Scope-prefix keys:
DB_HOST,DB_PORT,REDIS_URL,JWT_SECRET. - Avoid ambiguity: Use
API_BASE_URLinstead of justURL. - Group by service: Use a common prefix like
MYAPP_DB_,MYAPP_CACHE_. - Boolean values: Use
true/falseor1/0; neveryes/no(parsing varies).
The .env File Playbook
Step 1: Create Your Template
Always ship a .env.example file that documents every required variable without exposing real values:
# .env.example — copy to .env and fill in real values
# Database
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp_dev
DB_USER=myapp_user
DB_PASSWORD=change_me_now
# JWT / Auth
JWT_SECRET=your_super_secret_key_here
# External APIs
STRIPE_SECRET_KEY=sk_test_xxxxx
SENDGRID_API_KEY=SG.xxxxx
# Feature flags
ENABLE_CACHE=true
LOG_LEVEL=debug
Step 2: Protect Your Repository
- Add
.envto.gitignore - Add
.env.local,.env.*.localto.gitignore(for environment-specific overrides) - Run
git ls-files --others --exclude-standardto verify no env files are tracked - Scan repository history with
git-history-searchor gitleaks to confirm no secrets leaked previously
Step 3: Load Variables in Your Application
Use a dedicated library rather than manual process.env reads. It adds validation, default values, and type safety:
- Node.js:
dotenv+zodorjoifor schema validation - Python:
python-dotenv+pydantic-settings - Go:
godotenvorkoanf - Rust:
dotenvyorconfigcrate
Startup Validation Checklist
Every application should validate its environment before accepting traffic. Here is your must-have checklist:
- Required variables: Check every secret and connection string exists and is non-empty
- Type coercion: Parse booleans