guide8 min readupdated 2026-04-17

10 .env best practices every team should follow

Battle-tested rules for .env files: what to commit, what to rotate, how to structure secrets across dev, staging, and production, and the common mistakes that cause outages.

10 rules for .env files

Almost every production incident caused by a .env file is preventable. These are the rules we've seen teams adopt after getting burned.

1. Never commit secrets to git

Put .env, .env.local, and .env.production in .gitignore from day one. Commit a .env.example instead — keys only, no values. If you already pushed secrets, assume they're compromised and rotate them immediately.

2. Use .env.example as your source of truth

Every required key goes in .env.example. New hires copy it to .env.local, fill in values, and start running. The example generator can create this file from an existing .env in one click.

3. Generate secrets, never invent them

A JWT secret typed by a human has maybe 40 bits of entropy. A generated one has 256. Use crypto.randomBytes, OpenSSL, or a browser-based secret generator — never my-super-secret-key.

4. Rotate on any suspicion

If a secret was printed to logs, pasted in a ticket, or sent over Slack — rotate. The cost of rotation is low; the cost of a leaked prod DB is not.

5. One secret per purpose

Don't reuse JWT_SECRET as your session secret. Don't reuse your Stripe test key across projects. Blast radius stays small when secrets are scoped.

6. Validate at boot

Parse and validate .env on startup, and fail fast if a required key is missing. Tools like zod-env, envalid, and convict do this for Node.js. Pydantic's BaseSettings does it for Python.

7. Prefix public vs private clearly

Next.js uses NEXT_PUBLIC_. Vite uses VITE_. Create React App uses REACT_APP_. Every public variable is shipped to the browser — treat them as public by default, and name them accordingly.

8. Keep prod out of dev machines

Developers should never have the production .env locally. Use separate Supabase/AWS accounts for dev and prod, or scoped service accounts. Your local DATABASE_URL should point at a local Postgres, not staging.

9. Sync drift between environments

Staging and production diverge silently. Run a diff between the two files before every release — newly-added keys should exist in both, or your deploy will fail the moment a code path touches them.

10. Scan for leaks before you push

Before sharing an .env — in a ticket, Slack, or a deploy log — scan it for known secret patterns. AWS keys, Stripe live secrets, GitHub tokens, and private key blocks have recognizable shapes that scanners catch in seconds.

A safe team workflow

  1. Dev keeps .env.local (git-ignored).
  2. Repo ships .env.example (committed).
  3. CI/CD pulls production values from a secrets manager, not git.
  4. Every PR that adds a key also updates .env.example.
  5. Release checklist includes a .env diff between staging and prod.

What to do if a secret leaks

  1. Rotate immediately. Revoke the leaked key in the issuing service (AWS IAM, Stripe, GitHub, etc.).
  2. Remove from git history with git filter-repo or BFG. Force-push.
  3. Audit access logs for usage of the leaked key.
  4. Notify anyone affected if customer data was exposed.

Further reading

Related tools

Continue reading