guide8 min readupdated

10 .env best practices every team should follow

Rules for .env files: what to commit, what to rotate, how to structure secrets across dev, staging and production, and the 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, and don't reuse an API key or client secret across environments. 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.

FAQ

Is .gitignore enough to keep .env safe, or do I need something else?

.gitignore only stops future commits — it does nothing for a secret that's already in your git history. If you've ever committed a real .env, treat it as compromised: rotate every value in it, then rewrite history with git filter-repo or BFG to remove the blob.

How often should secrets be rotated if nothing has leaked?

There's no universal number, but a reasonable baseline is every 90 days for high-value credentials (database, payment provider, admin API keys) and on any team-member offboarding. Low-risk values, like a public analytics ID, don't need scheduled rotation.

Do these rules still apply to a solo project with no team?

Mostly yes — generated secrets, .gitignore, and leak scanning cost nothing and prevent the same mistakes. The rules you can relax solo are the process ones: strict secrets-manager RBAC and audit logs matter far less than a checklist made for coordinating multiple people.

What's the fastest way to check if I've already leaked a secret?

Run your .env through the leak checker before anything else — it pattern-matches AWS keys, Stripe secrets, GitHub tokens, and private-key blocks in seconds. For git history specifically, tools like gitleaks or truffleHog scan every past commit, not just the working tree.

Further reading

Related tools

Continue reading