Technology · Next.js
Next.js Environment Variables
Manage environment variables and configure Next.js for different environments.
TL;DR
- 01Use .env.local for environment variables in development.
- 02Variables prefixed NEXT_PUBLIC_ are exposed to browser.
- 03Server-only variables are only available on the server.
Environment Files
- Create .env.local for local development variables.
# .env.local DATABASE_URL=postgresql://user:password@localhost/db API_SECRET=my-secret-key - Create .env.production for production variables.
# .env.production DATABASE_URL=postgresql://user:password@prod/db API_SECRET=production-secret - Variables are loaded at build time for static files.
- Use .env.development to set variables for npm run dev only.
# .env.development NEXT_PUBLIC_API_URL=http://localhost:4000 LOG_LEVEL=debug - Use .env for shared defaults across all environments.
# .env (committed — no secrets) NEXT_PUBLIC_APP_NAME=My App NEXT_PUBLIC_SUPPORT_EMAIL=support@example.com - Priority order: .env.local overrides .env for the same variable name.
# .env.local values always win in local development
Public Variables
- Prefix with NEXT_PUBLIC_ to expose to browser.
# .env.local NEXT_PUBLIC_API_URL=https://api.example.com NEXT_PUBLIC_APP_NAME=My App - Access in client and server code.
function Component() { const apiUrl = process.env.NEXT_PUBLIC_API_URL; return <p>API: {apiUrl}</p>; } - Use for non-sensitive data only.
- Public variables are inlined at build time, not at runtime.
// process.env.NEXT_PUBLIC_API_URL becomes a string literal in the bundle const url = process.env.NEXT_PUBLIC_API_URL; // "https://api.example.com" - Use for things like Stripe publishable keys or analytics IDs.
NEXT_PUBLIC_STRIPE_KEY=pk_live_abc123 NEXT_PUBLIC_GA_ID=G-XXXXXXX
Server-Only Variables
- Variables without NEXT_PUBLIC_ are server-only.
# .env.local DATABASE_URL=postgresql://... API_KEY=secret-key - Access only in server-side code.
export async function GET() { const apiKey = process.env.API_KEY; // Safe: runs on server only } - Never available in browser or client components.
- Use server-only variables in server actions and route handlers.
"use server"; export async function deleteUser(id: string) { await db.user.delete({ where: { id } }); // process.env.DATABASE_URL is safe here } - Attempting to access server-only vars in client code returns undefined.
"use client"; // process.env.API_KEY is undefined — not leaked to browser
Config File Options
- Configure Next.js behavior in next.config.js.
// next.config.js module.exports = { // Enable React strict mode reactStrictMode: true, // Configure image optimization images: { domains: ['cdn.example.com'] }, // Environment variables env: { CUSTOM_VAR: process.env.CUSTOM_VAR } }; - Restart dev server after changes.
- Add custom HTTP headers for all routes.
module.exports = { async headers() { return [ { source: "/(.*)", headers: [{ key: "X-Frame-Options", value: "DENY" }] } ]; } }; - Set up URL redirects for old routes.
module.exports = { async redirects() { return [ { source: "/old-path", destination: "/new-path", permanent: true } ]; } }; - Allow images from external domains in next.config.js.
module.exports = { images: { remotePatterns: [{ hostname: "cdn.example.com" }] } }; - Configure basePath for apps hosted at a URL subpath.
module.exports = { basePath: "/blog" // All routes are now prefixed with /blog };
Best Practices
- Never commit .env.local to version control.
# .gitignore .env.local .env.development.local .env.test.local .env.production.local - Use .env.example for documentation.
# .env.example DATABASE_URL=postgresql://user:password@localhost/db NEXT_PUBLIC_API_URL=https://api.example.com - Validate environment variables on startup.
// lib/env.ts if (!process.env.DATABASE_URL) { throw new Error("DATABASE_URL is not set"); }
Tip: Use .env.example to document which environment variables are needed — commit it to version control.
Warning: Never commit .env.local files — they contain secrets. Use .gitignore to exclude them.