Skip to content
C.W.K.
Stream
Lesson 05 of 08 · published

Environment Variables in Production

~20 min · env, build vs runtime, Docker

Level 0Curious
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

Build-time vs runtime

Variable kindRead when?
NEXT_PUBLIC_*Build time — baked into the bundle
Server-onlyRuntime — read on every request

The Docker problem

Building one image and deploying it to staging + production with different settings? NEXT_PUBLIC_* values can't change between environments — they're already baked in. You either rebuild per environment or use runtime config strategies (e.g., proxy injects them, or you read from server only).

Loading order

  1. Already-set process.env
  2. .env.production.local / .env.development.local
  3. .env.local (skipped in test)
  4. .env.production / .env.development
  5. .env

Maintain a typed inventory of configuration with owner, secrecy, build-time or runtime binding, and required environments. Validate server variables on startup, expose public values intentionally, and rotate secrets without requiring source changes. After changing an environment value, request both new deployments and old instances to detect mixed state. If two values coexist during a rolling deploy, data formats and flags must tolerate that interval. Copying one .env file between environments collapses boundaries and invites production credentials into local tools. Conversely, building one image for promotion cannot support different NEXT_PUBLIC_ values after the client bundle already exists. Compare preview and production inventories without printing values, start with one required key missing, rotate a credential, and promote the same artifact where the contract allows it. Search logs, build output, source maps, and browser bundles for secret markers.

Code

Force runtime read for an env var·tsx
import { connection } from 'next/server';

export default async function Page() {
  await connection(); // opt into per-request rendering
  const apiUrl = process.env.API_URL; // re-read each request
  return <div>API: {apiUrl}</div>;
}
Vercel CLI for environment scopes·bash
vercel env add DATABASE_URL production
vercel env add DATABASE_URL preview
vercel env add DATABASE_URL development

External links

Exercise

Build a Docker image with one set of NEXT_PUBLIC_* values. Deploy it to two environments and confirm the values match (i.e., they're baked in). Refactor one to be a server-only var and re-deploy.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.