What is a .env file? And why it must never be public.
A .env file is a plain-text list of KEY=value settings that an application reads when it starts — above all its secrets: database passwords, API keys, signing keys. It keeps them out of the source code. It doesn’t keep them out of reach: if the file sits where a web server can serve it, anyone can download it.
What it looks like
# Database
DB_HOST=127.0.0.1
DB_DATABASE=shop
DB_USERNAME=shop
DB_PASSWORD=change-me
# Services
MAIL_PASSWORD=change-me
STRIPE_SECRET=change-me
APP_KEY=change-me
One setting per line, # for comments, quotes around values with spaces. Some loaders also accept export KEY=value and ${OTHER_KEY} references; the details vary by library.
How apps load it
Nothing in the operating system treats .env as special. A library reads it at startup and copies each value into the process environment:
- Laravel and Symfony load it out of the box.
- Node.js uses the
dotenvpackage, ornode --env-file=.envfrom Node 20.6 on. - Python uses
python-dotenv; Ruby thedotenvgem. - Docker Compose reads a
.envnext to the compose file for variable substitution, andenv_file:passes a file’s values into a container. - Front-end build tools (Next.js, Vite and others) read it at build time, and copy variables with a public prefix into the browser bundle — see public env variables.
Variants such as .env.local, .env.production and .env.development override each other in an order each framework defines. .env.example is different: a template with placeholder values, meant to be committed.
How .env files end up public
- The project folder is the web root. The web server then serves everything in it,
.envincluded — neither nginx nor Apache hides it by default. On Laravel: fix the document root. - Backup and editor copies —
.env.bak,.env.save,.env.old— left next to the original and sent as plain text. - Committed to git, then pushed to a public repository or deployed with an exposed .git directory.
- Copied into a build — a front-end bundle, or a Docker image built with
COPY . .and no.dockerignore.
Whichever way it got out, one file holds every key at once: database credentials, cloud, payment and email API keys, and the app’s signing secrets.
How to keep it private
- Point the document root at the app’s public folder, and keep
.envabove it. - Block dotfiles and backup copies in the web server: tested rules for nginx, Apache and Caddy.
- List
.envin.gitignoreand.dockerignore. If it was ever committed,git rm --cached .envstops tracking it, but history keeps the old copy — rotate what was in it. - Make it readable only by the user the app runs as, for example
chmod 600 .envwith that user as owner. - On managed platforms, prefer the platform’s environment variables or secret store to a file.
Check yours
DotenvScan checks a site from the outside for .env and its backup copies. To inventory every .env and config file across a whole Linux server, use ServerSecretVault’s scan.