How to Set Up .env Files
Your secrets live in one file. Here's how to set it up right.
TL;DR
Create a .env.local file in your project root with KEY=value pairs and add it to .gitignore. Most modern frameworks (Next.js, Vite) load .env files automatically. For plain Node.js, install dotenv and import it at the very top of your entry file.
File Naming Conventions
| File | Purpose | Commit to Git? |
|---|---|---|
| .env | Base defaults | Sometimes (no secrets) |
| .env.local | Local overrides with secrets | Never |
| .env.development | Development environment | Sometimes |
| .env.production | Production environment | Never |
| .env.example | Template with placeholder values | Yes |
Step-by-Step Setup
Create your .env.local file
In your project root, create .env.local:
# .env.local
# Database
DATABASE_URL=postgresql://localhost:5432/mydb
# API Keys
STRIPE_SECRET_KEY=sk_test_xxxxx
OPENAI_API_KEY=sk-xxxxx
# Public variables (exposed to browser in Next.js)
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_API_URL=http://localhost:3000/api
Add to .gitignore
Don't commit .env files with real secrets. Add these patterns:
# .gitignore
# Environment files
.env
.env.local
.env.*.local
.env.production
# Keep the example
!.env.example
Create an example file
.env.example acts as the template for anyone cloning your repo. Commit this one:
# .env.example - Copy to .env.local and fill in values
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
STRIPE_SECRET_KEY=sk_test_your_key_here
OPENAI_API_KEY=sk-your_key_here
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
Framework-Specific Setup
Next.js
Next.js loads .env files automatically. No installation needed.
// Access in server components, API routes, etc.
const apiKey = process.env.STRIPE_SECRET_KEY;
// Access in client components (must have NEXT_PUBLIC_ prefix)
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
Vite (React, Vue, Svelte)
Vite loads .env files automatically too, but uses a different prefix:
# .env.local
VITE_API_URL=https://api.example.com
// Access in code
const apiUrl = import.meta.env.VITE_API_URL;
Node.js (Express, etc.)
For plain Node.js, you'll need to install the dotenv package:
npm install dotenv
Then import it at the very top of your entry file. It must load before any other imports that read process.env:
// index.js or server.js - MUST be first import
import 'dotenv/config';
// or: require('dotenv').config();
// Now process.env has your variables
const port = process.env.PORT || 3000;
const dbUrl = process.env.DATABASE_URL;
Create React App
CRA uses REACT_APP_ as its prefix (not VITE_):
# .env.local
REACT_APP_API_URL=https://api.example.com
// Access in code
const apiUrl = process.env.REACT_APP_API_URL;
.env File Syntax
# Comments start with #
# Basic format: KEY=value (no spaces around =)
# Simple values
PORT=3000
NODE_ENV=development
# Strings with spaces need quotes
APP_NAME="My Awesome App"
# URLs don't need quotes
API_URL=https://api.example.com/v1
# Multi-line values use quotes
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA
-----END RSA PRIVATE KEY-----"
# Reference other variables (in some implementations)
BASE_URL=https://api.example.com
FULL_URL=${BASE_URL}/v1
Common syntax mistakes: spaces around = (KEY = value breaks parsing), missing quotes when the value has spaces (NAME=My App should be NAME="My App"), and trailing whitespace after the value (invisible but causes strange auth failures).
Loading Order
Most frameworks load .env files in this order (later files override earlier ones):
.env.env.local.env.developmentor.env.production(based on NODE_ENV).env.development.localor.env.production.local
Use .env.local for local secrets and .env for shared, non-sensitive defaults. That way teammates can commit .env with placeholder port numbers and you keep your real API keys out of git entirely.
Do I need to restart my dev server after changing .env?
Yes. Environment variables are loaded when your application starts. After changing .env.local, restart your dev server with npm run dev or equivalent.
Why isn't my variable showing up?
Start with the dev server restart. That's the culprit 80% of the time. If it's still missing, check that you put it in .env.local and not just .env. For browser-facing variables, confirm you're using the right prefix for your framework: NEXT_PUBLIC_ for Next.js, VITE_ for Vite, REACT_APP_ for CRA.
Should I commit .env files?
Never commit files with real secrets. .env.example is always safe to commit (it has placeholder values, not real ones). You can also commit a .env that contains only non-sensitive defaults like PORT=3000 or NODE_ENV=development. Keep .env.local and anything with real credentials out of git.
Related guides:Environment Variables Guide · How to Gitignore Secrets · How to Hide API Keys