Environment Variables
Store config and secrets in .env files; prefix with NEXT_PUBLIC_ only for values safe to expose.
Syntax
NEXT_PUBLIC_* is exposed to the browser; everything else is server-only.Next.js reads environment variables from .env files automatically. The key rule is about exposure:
- Plain variables (e.g.
DATABASE_URL) are server-only — never sent to the browser. - Variables prefixed
NEXT_PUBLIC_are inlined into client code and visible to anyone.
So only public, non-secret values should get the NEXT_PUBLIC_ prefix.
Example
# .env.local
DATABASE_URL=postgres://user:pass@localhost/db # server only
NEXT_PUBLIC_SITE_URL=https://example.com # exposed to browser
# Reading them in code:
// server component / action: process.env.DATABASE_URL
// client component: process.env.NEXT_PUBLIC_SITE_URLWhen to use it
- A developer stores a database connection string in .env.local so it is never committed to version control.
- A public Stripe publishable key is prefixed with NEXT_PUBLIC_ so the client-side checkout component can read it safely.
- A CI/CD pipeline sets production secrets as environment variables on the server so .env files need not be deployed.
More examples
Environment variable files
Variables without NEXT_PUBLIC_ are server-only; those with it are embedded in the client bundle.
# .env.local (gitignored — development secrets)
DATABASE_URL=postgres://user:pass@localhost/mydb
STRIPE_SECRET_KEY=sk_test_...
# .env (committed — non-secret defaults)
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_STRIPE_KEY=pk_test_...Read server-side env var
Server code accesses env vars via process.env at runtime; they are never sent to the client.
// app/api/db/route.ts (Server Component or Route Handler)
import { db } from '@/lib/db';
export async function GET() {
// process.env.DATABASE_URL is available server-side only
const count = await db.user.count();
return Response.json({ count });
}Client-safe public variable
NEXT_PUBLIC_ variables are replaced with their literal values at build time and are visible in the browser.
'use client';
// NEXT_PUBLIC_ vars are inlined at build time
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
export default function ApiStatus() {
return <p>API: {apiUrl}</p>;
}
Discussion