字节笔记本
2026年7月19日
Next.js Environment Variables: A Practical Reference
Environment variables in Next.js let you configure your app differently across environments (development, staging, production) without changing code. The main thing to understand is the split between server-only variables and client-accessible ones — and that the prefix NEXT_PUBLIC_ is what controls that split.
The NEXT_PUBLIC_ Prefix
Only variables prefixed with NEXT_PUBLIC_ are included in the client-side bundle. Everything else stays on the server.
# .env
# Accessible in both server and client code
NEXT_PUBLIC_API_URL=https://api.example.com
# Server-only
DATABASE_URL=postgresql://localhost:5432/mydb
SECRET_KEY=abc123// Client component — this works
const apiUrl = process.env.NEXT_PUBLIC_API_URL
// Client component — this will be undefined
const dbUrl = process.env.DATABASE_URLEnvironment File Hierarchy
Next.js loads .env files in this order (later files override earlier ones):
.env— defaults shared across all environments.env.local— local overrides (git-ignored).env.development— loaded whenNODE_ENV=development.env.production— loaded whenNODE_ENV=production.env.development.local— local overrides for development.env.production.local— local overrides for production
Build-Time vs Runtime
A common source of confusion: non-prefixed variables are available at build time for SSG pages, but at runtime for server-rendered pages. If you're doing static generation (output: 'export'), only NEXT_PUBLIC_ variables are available in the output.
TypeScript Support
Create a type definition file for autocomplete and type checking:
// src/env.d.ts
declare namespace NodeJS {
export interface ProcessEnv {
NEXT_PUBLIC_API_URL: string
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: string
DATABASE_URL: string
CLERK_SECRET_KEY: string
NODE_ENV: 'development' | 'production' | 'test'
}
}Validation with Zod
Validating environment variables at startup catches misconfiguration early:
import { z } from 'zod'
const envSchema = z.object({
NEXT_PUBLIC_API_URL: z.string().url(),
DATABASE_URL: z.string().url(),
CLERK_SECRET_KEY: z.string().min(1),
})
const env = envSchema.parse(process.env)Run this at app startup (server-side) so the app fails fast instead of silently using undefined.
Docker
Dockerfile
ENV NEXT_PUBLIC_API_URL=https://api.example.comDocker Compose
version: '3'
services:
app:
image: my-app
env_file:
- .env.productionRuntime Override
docker run -e NEXT_PUBLIC_API_URL=https://staging.example.com my-appNote that NEXT_PUBLIC_ variables are inlined at build time, so changing them at runtime via docker run -e won't affect client-side code unless you rebuild.
Common Mistakes
- Committing
.env.local— add it to.gitignoreimmediately. - Using
process.env.MY_VARin client code — it'll beundefinedwithout the prefix. - Expecting runtime changes to affect static exports — if you used
output: 'export', the values are baked in at build time. - Forgetting to restart the dev server after changing
.envfiles — Next.js reads them on startup.