# Best Practices for Environment Variables in Vercel Node.js Applications

> Optimize your Vercel Node.js app with environment variable best practices. Secure secrets, expose public vars with NEXT_PUBLIC, and avoid committing credentials for robust deployments.

- Repository: [Vercel/next.js](https://github.com/vercel/next.js)
- Tags: best-practices
- Published: 2026-02-21

---

**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`](https://github.com/vercel/next.js/blob/main/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.

```javascript
// 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.

```javascript
// 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`](https://github.com/vercel/next.js/blob/main/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 running `next dev`.
- **`.env.production`** – Loaded when running `next build` or `next 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`](https://github.com/vercel/next.js/blob/main/next.config.js). The configuration schema is defined in [`packages/next/src/server/config.ts`](https://github.com/vercel/next.js/blob/main/packages/next/src/server/config.ts).

```javascript
// 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`](https://github.com/vercel/next.js/blob/main/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`](https://github.com/vercel/next.js/blob/main/next.config.js). This ensures builds fail immediately if required secrets are absent.

```javascript
// 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:

```javascript
// 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:

```javascript
// 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.local`** for local development secrets and ensure it is listed in `.gitignore`.
- **Validate required variables** at build time in [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js) to prevent runtime failures.
- **Configure custom exposure** via [`next.config.js`](https://github.com/vercel/next.js/blob/main/next.config.js) only 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.