Next.js environment variables are more than just placeholders for API keys; they’re a fundamental part of how your application’s behavior can change between deployments without touching code.
Let’s see this in action. Imagine you have a Next.js app that talks to a remote API. You’ll likely have the API endpoint URL defined as an environment variable.
// pages/api/data.js
export default function handler(req, res) {
const apiKey = process.env.EXTERNAL_API_KEY;
const apiUrl = process.env.EXTERNAL_API_URL;
// Use apiKey and apiUrl to fetch data from an external service
// ...
res.status(200).json({ message: 'Data fetched successfully!' });
}
Your .env.local file might look like this:
EXTERNAL_API_KEY=your_secret_api_key_here
EXTERNAL_API_URL=https://api.example.com/v1
And your next.config.js might expose the URL to the client-side:
// next.config.js
module.exports = {
env: {
EXTERNAL_API_URL: process.env.EXTERNAL_API_URL,
},
};
This allows your frontend code to access process.env.EXTERNAL_API_URL (which Next.js bundles), while the EXTERNAL_API_KEY remains server-side only.
The core problem Next.js environment variables solve is configuration drift – the inevitable divergence of application settings across different environments (development, staging, production) and even different instances of the same environment. Instead of hardcoding values that need to be changed with each deployment, you externalize them. This makes your application more portable and secure.
Internally, Next.js handles environment variables in a few key ways:
- Loading: It loads variables from
.envfiles based on your current Node.js environment (.env,.env.development,.env.production,.env.local, etc.). The.env.localfile is specifically for local development secrets and is ignored by Git. - Server-Side Access: On the server (during Node.js execution), you can access any environment variable directly via
process.env.YOUR_VARIABLE_NAME. These are not exposed to the client. - Client-Side Exposure: For variables that need to be available in the browser, you must explicitly prefix them with
NEXT_PUBLIC_. Next.js then bundles these prefixed variables into your client-side JavaScript bundles. You can also configure which variables are exposed via theenvkey innext.config.js, as shown above.
The exact levers you control are:
- Naming Conventions: Using
NEXT_PUBLIC_for client-side variables and omitting it for server-side ones. .envFile Hierarchy: Understanding the precedence of.env.local>.env.production>.env.development>.env.next.config.jsenvproperty: Explicitly mapping environment variables to be available in the build process.- Deployment Platform Configuration: How your hosting provider (Vercel, Netlify, Docker, AWS, etc.) injects environment variables into your running application. This is crucial for production.
One common misconception is that NEXT_PUBLIC_ variables are inherently "safe" because they are exposed client-side. This is only true if the data they represent is not sensitive. For instance, a NEXT_PUBLIC_API_BASE_URL is fine, but a NEXT_PUBLIC_SECRET_API_KEY is a major security vulnerability. The NEXT_PUBLIC_ prefix is a bundling mechanism, not a security feature.
Understanding how to inject environment variables at build time versus runtime is the next logical step in mastering Next.js deployments.