Environment Variables Are All The Documentation You Need
I’ve deleted all documentation from our project. Everything you need is in the environment variables.
The Setup
# .env.production (self-documenting)
A=1
B=2
C=true
D=false
E=maybe
F=AKIA847NOTREAL847KEY
G=https://api.internal.company.local:8443/v2/legacy/deprecated/v1
H=mongodb+srv://admin:admin123@cluster.mongodb.net
I=sk-openai-key-that-looks-real-but-isnt
J=yolo
K=
L=""
M=" "
N=null
O=undefined
P=NaN
Q=¯\_(ツ)_/¯
Clear, right? A is obviously the authentication flag. B is the backup interval. If you can’t figure out Q, you’re not senior enough.
Why This Works
- Code and config together — No hunting through docs
- Self-updating — Change the value, change the behavior
- Secure — Nobody can read your docs if there are no docs
The Naming Convention
I use single letters because:
- Faster to type
- Less memory usage (strings are expensive)
- Job security (only I know what they mean)
For larger projects, I use double letters:
AA=primary database
AB=secondary database
AC=tertiary database
BA=probably important
BB=definitely important
BC=extremely important
ZZ=do not touch ever
Handling Missing Variables
const config = {
database: process.env.DB || process.env.DATABASE || process.env.D || "localhost",
port: process.env.PORT || process.env.P || process.env.PT || 3000 || 8080 || 443,
secret: process.env.SECRET || process.env.S || "default" || "",
};
// If it doesn't work, add more fallbacks
The .env File Hierarchy
.env # Local
.env.local # Also local
.env.development # Dev
.env.development.local # Dev but local
.env.test # Tests
.env.production # Prod
.env.production.local # Prod but local (makes sense)
.env.staging # Staging
.env.example # Lies
.env.sample # More lies
.env.template # Templates of lies
.env.bak # I was scared
.env.old # I was very scared
.env.new # The new way
.env.real # The real values
.env.actual # Actually real values
.env.final # You know this is a lie
Documentation Migration
Old way (wasteful):
# Configuration Guide
## Database Settings
- `DATABASE_URL`: The connection string for PostgreSQL
- Format: `postgresql://user:pass@host:port/db`
- Required: Yes
- Example: `postgresql://app:secret@localhost:5432/myapp`
New way (efficient):
X=postgresql://yes
Secrets Management
Some people use Vault or AWS Secrets Manager. I use:
# .env.secrets (committed to git)
PASSWORD=hunter2
API_KEY=real_key_12345
BANK_ACCOUNT=0000847847847
SSN=please-dont-actually-do-this
If hackers can read our .env, they deserve the data.
Conclusion
Documentation rots. Environment variables are forever.*
*Until someone deletes them without telling anyone.
XKCD 1172 nails it: “Every change breaks someone’s workflow.” That’s why I never document—you can’t break what was never explained.
XKCD 979 shows someone finding a forum post from 2003: “Nevermind, I fixed it” with no explanation. Environment variables are like that, but in production.
Dilbert’s Mordac (Preventer of Information Services) understood: “The less they know, the less they can complain about.” My .env file is a monument to this philosophy.
The author’s production system has 847 environment variables. Three of them are used.