Explainer

What is a .env file? Format, examples, and keeping it private.

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.

  1. What is a .env file?
  2. Env file examples
  3. Syntax rules
  4. .env, .env.local, .env.production…
  5. Creating and opening one
  6. Is a .env file secure?
  7. How .env files end up public

What is a .env file?

A .env file (said “dot env”) is a text file of environment variables, one KEY=value per line, kept in a project’s root folder. When the app starts, a library reads the file and puts each value into the process environment, where the code reads it as process.env.KEY, os.getenv("KEY") or env('KEY').

The point is to keep configuration that changes between machines — your laptop, staging, the live server — out of the code. That idea comes from the Twelve-Factor App: store config in the environment. A .env file is the convenient way to fill that environment, especially in development.

The whole file name is .env: there is no name before the dot and no other extension. Because it starts with a dot, Linux and macOS hide it — ls -a shows it, and so does Cmd+Shift+. in a Finder window.

Env file examples

A typical file, with comments:

# 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

Node.js

# .env
PORT=3000
DATABASE_URL=postgres://app:change-me@localhost:5432/app
SESSION_SECRET=change-me
# Node.js 20.6 and later read it without a package:
node --env-file=.env server.js

// Or with the dotenv package, as the first line of the app:
require('dotenv').config();
console.log(process.env.PORT); // "3000"

From Node 20.12 there is also process.loadEnvFile(), which loads .env from inside the code.

Python

# pip install python-dotenv
import os
from dotenv import load_dotenv

load_dotenv()                      # finds the nearest .env and loads it
db_url = os.getenv("DATABASE_URL")

Laravel and PHP

APP_NAME=Shop
APP_ENV=production
APP_KEY=base64:generated-by-php-artisan-key-generate
APP_DEBUG=false
APP_URL=https://shop.example.com

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=shop
DB_USERNAME=shop
DB_PASSWORD=change-me

Laravel loads it with the vlucas/phpdotenv library, which plain PHP projects can use too. Read values with env('DB_HOST') inside the files in config/ only: after php artisan config:cache the .env file is no longer loaded, and env() calls elsewhere stop seeing its values. What to do if a Laravel .env leaks: Laravel .env exposed.

Docker Compose

# .env, next to compose.yaml
APP_TAG=1.4.2
POSTGRES_PASSWORD=change-me
# compose.yaml
services:
  app:
    image: example/app:${APP_TAG}
    env_file: .env
  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

Compose uses the file twice here: it fills in ${…} references inside compose.yaml, and env_file: passes every value in it into the app container. Keep the file out of the image itself with a .dockerignore.

.env.example

The one env file that belongs in git: a template listing every variable the app needs, with empty or placeholder values. A new developer copies it and fills it in.

# .env.example — copy to .env and fill in. No real values here.
DATABASE_URL=
SESSION_SECRET=
MAIL_PASSWORD=
cp .env.example .env

Syntax rules

# A comment line
APP_NAME=Shop               # unquoted; most loaders drop the inline comment
GREETING="Hello, world"     # quote values with spaces or a #
RAW='no $expansion here'    # single quotes: taken literally
export LOG_LEVEL=info       # "export" is accepted, so a shell can source the file
PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----"

.env, .env.local, .env.production: which file is which

FileWhat it’s forCommit to git?
.envThe main file. In Laravel and most back ends it holds the real secrets; Next.js and Vite also use it for shared, non-secret defaults.Only if it holds no secrets
.env.localOverrides for your own machine.No
.env.development, .env.production, .env.testValues for one environment, picked by the framework’s mode.Only if they hold no secrets
.env.production.local and similarLocal overrides for one environment.No
.env.exampleA template with placeholder values.Yes

Which file overrides which differs between frameworks — Next.js and Vite, for instance, rank .env.local and .env.production differently — so check your framework’s documentation. Copies such as .env.bak, .env.save and .env.old are none of these: no framework reads them, and they are a common way secrets leak.

Creating and opening a .env file

Is a .env file secure?

No more than any other text file. It isn’t encrypted; it keeps secrets out of the code, not out of reach. What protects it is where it lives and who can read it:

How .env files end up public

  1. The project folder is the web root. The web server then serves everything in it, .env included — neither nginx nor Apache hides it by default. On Laravel: fix the document root.
  2. Backup and editor copies — .env.bak, .env.save, .env.old — left next to the original and sent as plain text.
  3. Committed to git, then pushed to a public repository or deployed with an exposed .git directory.
  4. Copied into a build — a front-end bundle (see public env variables), or a Docker image built with COPY . . and no .dockerignore.

Whichever way it got out, one file holds every key at once. If yours is exposed, here’s what to do now.

Check yours

DotenvScan requests /.env, its .production, .local and backup variants, and .env files in /api/ and /backend/, and tells you whether any of them downloads. To inventory every .env and config file across a whole Linux server, use ServerSecretVault’s scan.

Check your site now