How do environment variables work in Next.js?
Take a moment.
Say your answer out loud or write it down first — retrieval is what makes it stick. Reveal when you're ready.
Short answer
NEXT_PUBLIC_* variables inline into the client bundle and are readable in the browser. All others stay server-only — accessible in Server Components, Route Handlers, middleware. Load from .env files per environment; never expose secrets via NEXT_PUBLIC_.
Detailed explanation
Next.js loads .env.local (gitignored, highest priority outside CI), .env.development/.env.production per NODE_ENV, and .env for shared defaults. Prefixing with NEXT_PUBLIC_ makes a variable available client-side by string-replacing it at build time — meaning it becomes permanently visible in shipped JS: safe for public API base URLs and analytics IDs, catastrophic for keys. Server-only variables read via process.env.FOO work anywhere server code runs: Server Components, route handlers, server actions, getServerSideProps. Runtime vs build time matters for deployments: NEXT_PUBLIC_ vars bake in during build (changing them requires rebuild), while server vars on platforms like Vercel can change per deployment without rebuild. Best practices: validate required env at startup (zod schema), keep .env.example committed with placeholders, rotate any secret that ever touched NEXT_PUBLIC_.
Example
# .env.local
DATABASE_URL=postgres://... # server-only ✅
STRIPE_SECRET_KEY=sk_... # server-only ✅
NEXT_PUBLIC_API_BASE=/api/v1 # exposed to browser — public info only
# Server Component / route handler:
const db = connect(process.env.DATABASE_URL);Interview tip
Hammer the build-time inlining of NEXT_PUBLIC_ and the leaked-secret consequence. Then mention runtime-vs-build-time difference on hosting platforms.
Common mistakes
- Putting secrets behind NEXT_PUBLIC_ thinking it's 'protected'.
- Expecting NEXT_PUBLIC_ changes to apply without rebuilding.