guide6 min readupdated 2026-04-17

How to use dotenv in Node.js, Next.js, and Django

Step-by-step examples for loading .env files with dotenv in Node.js, Next.js (App Router), Python/Django, Rails, and Laravel. Includes load order and override rules.

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.js

Option 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:

  1. .env — committed defaults
  2. .env.local — your machine, always loaded (never in tests)
  3. .env.development or .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 + server

Read 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=production

Need to ship the whole .env to Kubernetes? Convert it to a K8s Secret manifest in one click.

Load-order rules (across stacks)

  1. Later files override earlier files.
  2. Shell environment beats .env files (almost always).
  3. .env.local is intentionally ignored by tests in most frameworks.
  4. Production builds usually don't read .env at 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.

Related tools

Continue reading