Commit a .env.example that lists every variable your app needs, with safe placeholder values and a short comment. Git-ignore the real .env and any .local files. The example file documents your config contract without exposing a single real credential.
Why the split exists
The twelve-factor method says config varies between deploys and code does not, and it gives a litmus test: could you open source the codebase at any moment without exposing credentials? A real .env in the repository fails that test.
The same text warns that config files kept out of version control still have weaknesses, because it is easy to commit one by mistake. The Next.js docs say the default create-next-app template adds all .env files to .gitignore, and that you almost never want to commit them. Vite recommends adding *.local to .gitignore.
What goes in the example file
List every variable the app reads. Use obviously fake placeholders, such as changeme or an empty value, never a real key and never a value that looks real but was valid once.
Add a short comment for each: what it is, where to get it, and whether it is safe to expose to a browser. For frameworks that bundle prefixed variables into client code, mark those clearly, because the Vite and Next.js docs both describe prefixed values as ending up in the client bundle.
Mark required versus optional. A new teammate then knows which gaps stop the app from starting.
Rules for placeholders
- No real hostnames that point at production.
- No default admin passwords that might work if someone copies the file as is.
- No sample JWT secrets. A weak example secret tends to get copied into real environments.
- Prefer a value that makes the app fail loudly over one that quietly works insecurely.
Keep it in sync
An example file that drifts from reality teaches the wrong thing. Add a CI step that reads variable names used in code and compares them with the names in .env.example. A mismatch fails the build. This also catches the quiet addition of a new secret that nobody documented.
Onboarding without sharing secrets
Tell new developers to copy the example to .env and fill in values from your secrets service, using their own development credentials where the provider supports it. Do not send a working .env over chat or email. A message thread is not a controlled store, and nobody can revoke it.
Check what is already in history
If a real .env was ever committed, ignoring it now does not remove the old copy from history. Rotate the credentials it held. Then decide whether rewriting history is worth the disruption. Rotation is the part that actually closes the exposure.
A sample file
A good example file has a comment line above each key, such as whether it is required and whether a browser may see it. Keys are listed in groups: database, third-party services, public client values. Real values are blank or obvious placeholders. The file is short enough that a new teammate reads it in two minutes.
Add a gate
A pull request gate can block commits that add files matching .env patterns outside the example file. Our hosted demo shows how a gate decides whether a change may merge.
Try it yourself
Click through it at your own pace, or open it full screen. Watch how a rule blocks a change before it merges, and think about a rule for stray env files.
Quick check
Should .env.example contain real values?
No. Use placeholders and comments. Real values belong in your secrets service or deployment environment, not in the repository.
Is ignoring .env enough after it was committed once?
No. The old commit still holds the values. Rotate the credentials, then consider history cleanup.
Sources
- The Twelve-Factor App, III. Config
- Next.js documentation, Environment Variables
- Vite documentation, Env Variables and Modes
Last reviewed: 19 October 2026.