How to use dotenv — one guide, every stack
Every modern framework has a blessed way to load .env files. The patterns are 90% identical — you install a library, call a load function, then read from process env. Here's the quickstart for each stack.
Node.js
Two options:
Option A — Native (Node 20+)
node --env-file=.env server.js
# or multiple files (later overrides earlier)
node --env-file=.env --env-file=.env.local server.jsOption B — dotenv package
npm install dotenv
// server.js — at the very top
require('dotenv').config();
// or with ESM:
import 'dotenv/config';
console.log(process.env.DATABASE_URL);Next.js (App Router)
Next.js reads .env files automatically. No import needed. The load order is:
.env— committed defaults.env.local— your machine, always loaded (never in tests).env.developmentor.env.production— env-specific
Variables are server-only by default. To expose to the browser, prefix with NEXT_PUBLIC_:
# .env.local
DATABASE_URL=postgres://localhost/app # server only
NEXT_PUBLIC_API_URL=https://api.example.com # browser + serverRead them like anywhere else: process.env.DATABASE_URL, process.env.NEXT_PUBLIC_API_URL.
Python / Django
pip install python-dotenv
# settings.py
from pathlib import Path
from dotenv import load_dotenv
import os
load_dotenv(Path(__file__).resolve().parent.parent / '.env')
SECRET_KEY = os.environ['SECRET_KEY']
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ['DATABASE_NAME'],
},
}Ruby / Rails
# Gemfile
group :development, :test do
gem 'dotenv-rails'
end
# .env (auto-loaded at boot)
DATABASE_URL=postgres://localhost/app
# Access anywhere
ENV['DATABASE_URL']Laravel
Laravel ships with vlucas/phpdotenv. The .env file is read once at boot. Access only from config files:
# .env
APP_KEY=base64:...
DB_CONNECTION=mysql
DB_DATABASE=laravel
// config/database.php
'database' => env('DB_DATABASE', 'forge'),Never call env() outside config files in production — config:cache freezes values at build time.
Go
// go.mod
require github.com/joho/godotenv v1.5.1
// main.go
import "github.com/joho/godotenv"
func main() {
godotenv.Load()
dbURL := os.Getenv("DATABASE_URL")
}Docker / docker-compose
# docker-compose.yml
services:
api:
env_file:
- .env
# or inline:
environment:
- NODE_ENV=productionNeed to ship the whole .env to Kubernetes? Convert it to a K8s Secret manifest in one click.
Load-order rules (across stacks)
- Later files override earlier files.
- Shell environment beats
.envfiles (almost always). .env.localis intentionally ignored by tests in most frameworks.- Production builds usually don't read
.envat runtime — the host injects vars.
When in doubt, use the .env merger to preview what your final config will look like.
Next steps
If a variable doesn't load, walk through how to fix .env file errors. For team-wide hygiene, .env best practices is the next read.