env
Env Variables: The Complete Playbook for Developers & DevOps
Environment variables are the backbone of modern application configuration. Whether you are deploying a Node.js microservice, spinning up a Docker container, or managing infrastructure on Kubernetes, understanding env is non-negotiable. This playbook gives you everything you need — from basics to advanced patterns — in one authoritative reference.
Key Takeaways
- Separate config from code: Never hard-code secrets, API keys, or environment-specific values directly into your source files.
- Use .env files locally: Store per-environment variables in
.envfiles and add them to.gitignoreimmediately. - Validate at startup: Failing fast by validating required env vars on application boot prevents subtle runtime errors.
- Follow the 12-Factor App methodology: Env vars are the official configuration mechanism recommended for modern cloud-native apps.
- Rotate secrets regularly: Treat every env variable containing credentials as a rotating secret, not a static constant.
- Dockerize carefully: Use
--env-fileor build-timeARGvs. runtimeENVstrategically to avoid leaking build secrets into images. - Audit before deployment: Run a pre-deploy checklist to confirm every required variable is set and every secret is masked in logs.
What Is an Environment Variable?
An environment variable is a dynamically named value stored in the operating system or runtime layer that any running process can read. Unlike configuration files checked into version control, env vars live outside the application codebase — typically managed by the hosting platform, CI/CD pipeline, or a dedicated secrets manager.
Common examples include:
DATABASE_URL— connection string for your databaseAPI_KEY— third-party service credentialsNODE_ENV— distinguishes development from productionPORT— the port your application binds toJWT_SECRET— signing key for authentication tokens
Why Environment Variables Matter
Security
Hard-coded credentials are one of the most common causes of security breaches. Env vars keep sensitive data out of your repository, meaning a git leak cannot expose your secrets. When combined with a proper secrets manager or platform-level injection, the attack surface shrinks dramatically.
Portability
Same codebase, multiple environments. A single application can run identically across local development, staging, and production by simply changing the environment variables it reads at startup — no code changes required.
Compliance
Standards such as SOC 2, HIPAA, and GDPR require that credentials not be stored in plaintext within source code repositories. Env vars (especially when managed by a vault) satisfy these audit requirements.
.env Files: The Developer's First Tool
The .env file is the most widely adopted pattern for local development. It is a plain-text file placed at the project root that key-value pairs are parsed by your framework or a companion library.
Correct Syntax
# .env.example — share this with your team
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
API_KEY=
NODE_ENV=development
PORT=3000
JWT_SECRET=change-this-before-production
LOG_LEVEL=debug
Rules to follow:
- No spaces around the
=sign - Quote values containing special characters:
TOKEN="my secret value"
li>Comment lines start with - Never commit the actual
.envfile — commit.env.exampleinstead
#
Add .env to .gitignore Immediately
# .gitignore
.env
.env.local
.env.*.local
Reading Env Vars Across Languages
| Language / Runtime | Read Method | Load Library | Validation Tip |
|---|---|---|---|
| Node.js | process.env.VAR_NAME |
dotenv or dotenv-expand |
Use zod or joi to validate at startup |
| Python | os.environ["VAR_NAME"] |
python-dotenv |
Use pydantic-settings for typed validation |
| Go | os.Getenv("VAR_NAME") |
godotenv or viper |
Check for empty strings and exit with clear error |
| Ruby | ENV["VAR_NAME"] |
dotenv-rails gem |
Use Config::Validate or similar gem |
| Bash / Shell | $VAR_NAME |
None (built-in) | Use set -u to treat unset vars as errors |
| Docker | $VAR_NAME in Dockerfile |
--env-file flag |
Prefer ARG for build-time, ENV for runtime |
Env Vars in Docker and Containers
Container orchestration shifts env var management from files to the platform. Understanding the Docker lifecycle is critical.
Build-Time vs. Runtime Env Vars
ARG (Build-Time) |
ENV (Runtime) |
|
|---|---|---|
| Purpose | Passed during docker build |
Available to the running container |
| Visible in image | No — stripped after build | Yes — readable from inside the container |
| Security | Preferred for secrets used only at build time | Inject secrets at deploy time via platform |
| Override | --build-arg KEY=value |
--env or --env-file |
Docker Compose Example
version: '3.8'
services:
app:
build: .
env_file:
- .env
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
secrets:
- jwt_secret
Best Practices for Containerized Envs
- Never bake secrets into a Docker image layer — use
ARGwith--secretor mount at runtime - Use
env_filefor bulk local config andenvironmentfor overrides - Set
secretsin Docker Swarm or Kubernetes Secret objects for production - Scan images with
trivyorgrypeto detect leaked env values in layers
Production Deployment Strategies
Platform-Level Injection
Most modern platforms inject env vars without any file