Best Practices for Environment Variables in Vercel Node.js Applications
Store sensitive secrets in Vercel's Environment Variables UI without any prefix, expose public values to the browser using the NEXT_PUBLIC_ prefix, and never commit real credentials to your repository.
Managing configuration securely is critical when deploying Node.js applications to Vercel. The Next.js framework, maintained in the vercel/next.js repository, provides built-in conventions for handling environment variables that automatically separate server secrets from public client data. Understanding these patterns ensures your application remains secure while maintaining flexibility across local development and production deployments.
Understand the NEXT_PUBLIC_ Prefix Convention
Next.js uses a strict naming convention to determine which variables reach the browser. This behavior is documented in docs/02-pages/02-guides/environment-variables.mdx and enforced by the framework's compiler.
Public Variables (NEXT_PUBLIC_)
Variables prefixed with NEXT_PUBLIC_ are statically replaced in the client bundle at build time. Use these for non-sensitive values that your React components need directly.
// components/Widget.js
export default function Widget() {
const apiUrl = process.env.NEXT_PUBLIC_API_URL; // Accessible in browser
return <div>API: {apiUrl}</div>;
}
Server-Only Variables
Variables without the NEXT_PUBLIC_ prefix remain server-side only. The bundler explicitly strips these from client code to prevent accidental leakage.
// pages/api/users.js
export default async function handler(req, res) {
const dbUrl = process.env.DATABASE_URL; // Never exposed to client
// Database logic here
}
Keep Secrets Out of Source Control
Never commit real secrets to your Git repository. Instead, store them in Vercel's Environment Variables UI under Project Settings. These values are encrypted and injected into process.env at both build and runtime without appearing in built assets.
For local development, create a .env.local file which is automatically ignored by Next.js git templates. This file takes precedence over all other environment files during local execution.
Leverage .env Files for Local Development
According to the loader implementation in packages/next/src/server/lib/environment.ts, Next.js automatically loads environment files in a specific priority order:
.env.local– Loaded in all environments, overriding other files. Use this for local secrets that must never be committed..env.development– Loaded only when runningnext dev..env.production– Loaded when runningnext buildornext start.
When you deploy to Vercel, variables defined in the dashboard override values in .env.production, ensuring production secrets remain distinct from your codebase.
Configure Custom Exposure in next.config.js
In rare cases where you must expose a variable to the client without the NEXT_PUBLIC_ prefix, you can explicitly define it in next.config.js. The configuration schema is defined in packages/next/src/server/config.ts.
// next.config.js
module.exports = {
env: {
// Exposed to client as process.env.CUSTOM_API_ENDPOINT
CUSTOM_API_ENDPOINT: process.env.CUSTOM_API_ENDPOINT,
},
};
Prefer the NEXT_PUBLIC_ convention when possible; manual configuration in next.config.js is more error-prone and harder to maintain.
Manage Preview and Production Environments
Vercel supports distinct variable scopes for different deployment contexts. Use the CLI or dashboard to set:
- Preview variables for pull-request deployments (
vercel env add <key> preview). - Production variables for your live site (
vercel env add <key> production).
When you modify a variable through the Vercel UI, the platform automatically triggers a new deployment to ensure the latest configuration is active.
Validate Configuration at Build Time
Protect your CI/CD pipeline from missing configuration by adding validation logic to next.config.js. This ensures builds fail immediately if required secrets are absent.
// next.config.js
if (!process.env.DATABASE_URL) {
throw new Error('Missing DATABASE_URL – set it in Vercel Environment Variables');
}
module.exports = {
// your config
};
Access Patterns in Code
Always check the runtime context before accessing sensitive variables. In API routes (server-only), you can safely access secrets:
// pages/api/secure.js
export default function handler(req, res) {
const secret = process.env.SECRET_KEY;
// Use secret for authentication or database access
}
In React components (client-side), only NEXT_PUBLIC_ variables will have values:
// components/PublicInfo.js
export default function PublicInfo() {
// Works: process.env.NEXT_PUBLIC_API_URL
// Undefined: process.env.SECRET_KEY
return <div>{process.env.NEXT_PUBLIC_API_URL}</div>;
}
Summary
- Use
NEXT_PUBLIC_exclusively for values that are safe to expose in browser JavaScript. - Store secrets in Vercel's Environment Variables UI without any prefix to keep them server-side only.
- Use
.env.localfor local development secrets and ensure it is listed in.gitignore. - Validate required variables at build time in
next.config.jsto prevent runtime failures. - Configure custom exposure via
next.config.jsonly when the naming convention cannot be used.
Frequently Asked Questions
What happens if I access a server-only variable in client code?
The variable returns undefined. Next.js intentionally strips non-prefixed environment variables from the client bundle during the build process to prevent accidental secret leakage.
Can I use .env.production files on Vercel?
Yes, but Vercel Environment Variables defined in the dashboard take precedence over .env.production files during the build. Use .env.production for default values, but always store actual secrets in the Vercel UI.
How do I share environment variables between multiple Vercel projects?
Use the Vercel CLI (vercel env ls and vercel env add) to script the transfer of variables, or maintain a secure external secrets manager that both projects reference. Never share variables by committing them to a shared repository.
Are environment variables encrypted at rest?
Yes. According to the Vercel platform architecture, variables stored in the Environment Variables UI are encrypted at rest and only decrypted during the build process or within the serverless runtime environment. They are never exposed in build artifacts or edge caches.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →