SCREAMING_SNAKE_CASE: the POSIX convention
In Unix shells, environment variables have been named in uppercase with underscores by
convention since the 1970s. PATH, HOME, USER.
Sticking to that convention guarantees compatibility with any language, framework and
orchestration tool.
12-factor's factor III
The 12-factor manifesto states that configuration must live in environment variables, not in hardcoded files. This separates code from config and lets the same binary run in dev, staging and prod just by changing the variables.
Recommended structure
<APP>_<AREA>_<PURPOSE>. Examples: APP_DB_URL,
APP_REDIS_HOST, APP_AWS_REGION,
APP_MAIL_SMTP_HOST. The prefix prevents collisions; the area groups
visually; the purpose identifies.
Conventional variables
- NODE_ENV: development, production, test (Node).
- DATABASE_URL: full connection string.
- PORT: port to listen on (PaaS sets it).
- LOG_LEVEL: debug, info, warn, error.
- TZ: time zone (default UTC).
- HTTP_PROXY, HTTPS_PROXY: outbound proxies.
Booleans as strings
Env vars are always strings. For booleans, the convention is "true" /
"false" or "1" / "0". Never compare with
== true in JavaScript: the string "false" is truthy. Use
helpers like parseBool(env.FEATURE_FLAG).
Secrets vs config
Secrets (passwords, API keys, tokens) shouldn't live in committable .env
files. Use .env.local (gitignored) in dev and a secret manager (Vault, AWS
Secrets Manager, GCP Secret Manager) in prod. Rotation should be part of the operational
process.
Validate at boot
Your app should fail fast if a critical variable is missing. Libraries like
envalid (Node), pydantic-settings (Python),
dotenv-rb + validators (Ruby) check types and presence at startup. Better a
clear crash than a null pointer on the first request.
Per-environment variables
Keep the list of variables identical across environments; change values. If
APP_FEATURE_BETA exists in prod but not staging, add it even with
false. Prevents divergent behavior between environments.