All posts
Security1 June 20265 min read

Why you should never commit .env files — and what to do instead

The one-line mistake that costs companies millions

It happens more than you'd think. A developer clones a repo, creates a .env file, runs the project locally, then adds everything to a commit. git add . — done. The .env goes in. It gets pushed. Nobody notices for weeks.

Then an attacker finds it.

In 2022, Heroku and Travis CI suffered credential leaks that started with secrets exposed in repositories. In 2023, a major fintech startup had their entire AWS account drained because a developer had accidentally committed a .env.production file to a *private* repo — which was later made public during a team migration. The damage: $47,000 in AWS charges in 18 hours.

These aren't edge cases. According to GitGuardian's 2025 State of Secrets Sprawl report, over 12.8 million secrets were found in public GitHub repos in a single year.


Why git is particularly dangerous for secrets

Most developers understand "don't push secrets". What they miss is git history.

Even if you delete the .env file in the next commit, the secret is still in your git history. Anyone who clones the repo can run:

bash
git log --all --full-history -- .env
git show <commit-hash>:.env

And there it is. Deleting a file from the working tree doesn't remove it from history. You'd need to rewrite history with git filter-branch or BFG Repo Cleaner, rotate every secret in that file, and hope no one cloned between the push and the fix.


The .gitignore trap

The most common defence is adding .env to .gitignore. This works — but only if you do it before the first commit. If .env has ever been tracked, git continues to track it even after you add it to .gitignore.

bash
# This does NOT stop tracking if .env was already committed:
echo ".env" >> .gitignore

# You also need to remove it from the index:
git rm --cached .env
git commit -m "stop tracking .env"

The safer approach: create .gitignore *before* your first git add.


The right pattern: .env.example

The standard solution is the .env.example (or .env.template) pattern:

1. Create a .env.example file with all the keys your app needs, but no real values:

bash
# .env.example — commit this
DATABASE_URL=
JWT_SECRET=
OPENAI_API_KEY=
STRIPE_SECRET_KEY=

2. Add .env to .gitignore — never commit it.

3. Document in your README: "Copy .env.example to .env and fill in your values."

This way, new team members know exactly what variables are required without ever seeing a real secret.


The missing key problem

The .env.example pattern has one weakness: it relies on humans staying in sync. A developer adds a new variable, updates their local .env, forgets to update .env.example. The next developer clones the repo, copies the example file, runs the project, and hits a cryptic error because REDIS_URL is missing.

ENV Manager Pro solves this with its built-in missing key checker. Open two files side by side and it shows you exactly which keys are in .env.example but missing from your .env:

Comparing .env ↔ .env.example

✓  DATABASE_URL
✓  JWT_SECRET
✗  REDIS_URL          ← MISSING in your .env
✗  OPENAI_API_KEY     ← MISSING in your .env

No more mysterious runtime crashes because someone forgot to update the example.


What about private repos?

Don't assume private repos are safe. Private repos can become public (accidentally or intentionally). Your company might be acquired. GitHub/GitLab accounts get compromised. Third-party CI tools (Travis, CircleCI, etc.) need read access to your repo — you're trusting their security too.

Treat every repo as if it could become public tomorrow.


The production secret problem

Development secrets are bad enough. Production secrets in git are catastrophic. Your production DATABASE_URL with real user data, your live STRIPE_SECRET_KEY that can initiate refunds, your JWT_SECRET that signs every auth token in your system.

For production, the right answer is a proper secrets manager:

  • AWS Secrets Manager / AWS Parameter Store — if you're on AWS
  • Doppler or Infisical — dedicated secrets platforms with audit trails
  • Vault by HashiCorp — for large teams with compliance requirements

ENV Manager Pro's Pro tier can pull directly from all of these into your local .env for development, so you never need to copy-paste production credentials manually.


The quick checklist

Before every push, ask yourself:

  • [ ] Is .env in my .gitignore? Has it *ever* been committed?
  • [ ] Did I run git status and check there's no .env* file in the staged list?
  • [ ] Are my production secrets only in a secrets manager — not in any file anywhere?
  • [ ] Does .env.example have all the keys a new developer would need?

These four questions take 30 seconds and can prevent a very expensive day.

Manage your secrets the right way

ENV Manager Pro is free to install — no account, no config, works in 30 seconds.