$ man how-to/env-files-explained
Securitybeginner
Environment Files Explained
What .env files are, why they matter, and how to set them up without leaking secrets
What an .env File Actually Is
An .env file is a plain text file that stores configuration values your application needs to run. API keys, database passwords, service URLs, feature flags. One key-value pair per line. No quotes needed (though some parsers accept them). No special syntax.
The file sits in your project root and never gets committed to Git. Your code reads from it using process.env.VARIABLE_NAME in Node.js or os.environ in Python. The values exist only on your machine. Your teammate has their own .env with their own keys. Production has its own set on the hosting platform.
The name starts with a dot, which makes it a hidden file on Mac and Linux. That is intentional. It should not be visible by default because it contains secrets.
PATTERN
Why You Need One
Three problems .env files solve.
First, security. API keys hardcoded in source files end up on GitHub. Bots scrape public repos for exposed keys within minutes of a push. AWS keys get stolen. Stripe keys get stolen. It happens constantly. .env files keep secrets out of version control entirely.
Second, portability. Your local machine, your staging server, and your production server all need different database URLs, different API endpoints, different feature flags. Same codebase, different environment variables. You deploy the same code everywhere and the .env file tells it how to behave.
Third, collaboration. Your teammate uses their own API keys. Your CI pipeline uses service account keys. Nobody shares credentials through Slack or email. Everyone has their own .env file with their own values.
CODE
Setting One Up
Step 1: Create the file in your project root.
touch .env
Step 2: Add your variables. One per line. No spaces around the equals sign.
API_KEY=sk_live_abc123
DATABASE_URL=postgres://user:pass@localhost:5432/mydb
NEXT_PUBLIC_SITE_URL=http://localhost:3000
DEBUG=true
Step 3: Add .env to your .gitignore immediately. This is non-negotiable.
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
echo ".env*.local" >> .gitignore
Step 4: Install a loader if your framework does not have one built in. Next.js loads .env files automatically. For other Node.js projects, use dotenv:
npm install dotenv
Then at the top of your entry file:
require('dotenv').config()
Step 5: Access variables in your code.
Node.js: process.env.API_KEY
Python: os.environ.get('API_KEY')
Next.js (client-side): process.env.NEXT_PUBLIC_SITE_URL
The NEXT_PUBLIC_ prefix in Next.js means the variable is exposed to the browser. Without that prefix, it stays server-side only. This matters. Do not put secret keys behind NEXT_PUBLIC_.
PATTERN
The .env File Hierarchy
Most frameworks support multiple .env files with a loading priority. Next.js loads them in this order, with later files overriding earlier ones:
.env (base defaults, committed to repo if no secrets)
.env.local (local overrides, never committed)
.env.development (only in dev mode)
.env.development.local (local dev overrides)
.env.production (only in production builds)
.env.production.local (local production overrides)
The .local files always override non-local files. The environment-specific files override the base .env. This lets you commit safe defaults in .env while keeping secrets in .env.local.
A common pattern: .env has NEXT_PUBLIC_SITE_URL=https://yoursite.com as the production default. .env.local overrides it to http://localhost:3000 for local development. No code changes needed to switch between environments.
PRO TIP
The Mistakes That Leak Secrets
Mistake 1: Forgetting to add .env to .gitignore before the first commit. Once a file is tracked by Git, adding it to .gitignore later does not remove it from history. You need git rm --cached .env to untrack it, then force push. If you already pushed to a public repo, rotate every key in that file immediately. The old keys are in Git history forever.
Mistake 2: Using NEXT_PUBLIC_ prefix on secret keys. NEXT_PUBLIC_STRIPE_SECRET_KEY is visible in the browser bundle. Anyone can inspect it. Only use the public prefix for values that are safe to expose, like your site URL or a public API key.
Mistake 3: Sharing .env files through Slack or email. Use a password manager, a secrets vault, or a secure sharing tool. .env files in chat histories get indexed, cached, and backed up in places you cannot control.
Mistake 4: Not creating a .env.example file. This is a template showing which variables your app expects, without the actual values. Commit this to the repo so new developers know what to fill in.
API_KEY=
DATABASE_URL=
NEXT_PUBLIC_SITE_URL=http://localhost:3000
Mistake 5: Logging environment variables during debugging and forgetting to remove the log statements. console.log(process.env) dumps every secret to whatever logging service you use.
PATTERN
Production Environment Variables
In production, you do not use .env files. You set environment variables directly on your hosting platform.
Vercel: Settings > Environment Variables. Add each key-value pair. Choose which environments it applies to (Production, Preview, Development).
Railway: Variables tab in your service settings.
AWS: Parameter Store or Secrets Manager.
The principle is the same everywhere. Secrets live in the platform, not in files. Your code reads from process.env regardless of where the values come from. Locally they come from .env. In production they come from the platform. Your code does not need to know the difference.
related guides