Skip to content

Next.js Environment Variables Not Working

Problem

Environment variables in Next.js can be problematic when they appear as undefined. This commonly occurs when using the process.env.YOUR_VARIABLE syntax, even when the variables are properly defined in .env.local or other environment files.

Root Cause

Next.js handles environment variables differently between server-side and client-side code, and there's an important distinction between build-time and runtime variables.

Key Facts

  • Next.js replaces process.env.* at build time, not runtime
  • Environment variables without the NEXT_PUBLIC_ prefix are only available server-side
  • Client-side code can only access variables prefixed with NEXT_PUBLIC_

Solutions

For variables that need to be accessible in the browser, prefix them with NEXT_PUBLIC_:

env
# .env.local
NEXT_PUBLIC_API_URL=http://localhost:3000/api
NEXT_PUBLIC_ANALYTICS_ID=123456789
javascript
// In your component
console.log(process.env.NEXT_PUBLIC_API_URL); // Works in browser

Important

Always restart your development server after modifying environment variables:

bash
npm run dev

2. Server-Side Environment Variables

For sensitive data that should not be exposed to the client:

env
# .env.local
DATABASE_URL=your_database_connection_string
API_SECRET=your_secret_key
javascript
// pages/api/data.js (Server-side only)
export default function handler(req, res) {
  const dbUrl = process.env.DATABASE_URL; // Only accessible server-side
  res.status(200).json({ data: 'secure' });
}

3. Next.config.js Configuration (Legacy Approach)

For Next.js versions prior to 9.4, you can use next.config.js:

javascript
// next.config.js
module.exports = {
  env: {
    CUSTOM_KEY: process.env.CUSTOM_KEY,
  },
};

Deprecation Notice

This approach exposes variables to both server and client, which may not be secure for sensitive data. Use NEXT_PUBLIC_ prefix instead for modern Next.js versions.

4. Runtime Environment Variables

For values that need to change at runtime (not just build time), use a custom solution:

javascript
// app/layout.tsx
import { PublicEnvScript } from 'next-runtime-env';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head>
        <PublicEnvScript />
      </head>
      <body>
        {children}
      </body>
    </html>
  );
}
javascript
// app/client-page.tsx
'use client';
import { env } from 'next-runtime-env';

export default function SomePage() {
  const apiUrl = env('NEXT_PUBLIC_API_URL');
  return <div>API URL: {apiUrl}</div>;
}

5. Server-to-Client Prop Passing

For maximum control and security:

javascript
// pages/index.js (Server Component)
export default function HomePage({ apiUrl }) {
  return <ClientComponent apiUrl={apiUrl} />;
}

export async function getServerSideProps() {
  return {
    props: {
      apiUrl: process.env.API_URL // Pass server env to client as prop
    }
  };
}

Common Pitfalls and Debugging

Common Mistakes

  1. Forgetting to restart the dev server after environment changes
  2. Typos in variable names - use console.log(process.env) to debug
  3. Incorrect file location - .env.local should be at project root
  4. Using React app conventions - REACT_APP_ prefix doesn't work in Next.js
javascript
// Debug all environment variables
console.log('All env variables:', process.env);

Environment File Hierarchy

Next.js loads environment variables in this order:

  1. .env.local (for all environments)
  2. .env.development / .env.production (environment-specific)
  3. .env (base environment)

Best Practices

  • Use .env.local for local development (add to .gitignore)
  • Use .env.production for production-specific variables
  • Never commit sensitive data to version control

Production Deployment Considerations

When deploying to platforms like Vercel, Heroku, or Docker:

bash
# Set environment variables in your deployment platform
vercel env add NEXT_PUBLIC_API_URL

Production Warning

NEXT_PUBLIC_ variables are embedded at build time. To change them, you must rebuild your application. For truly dynamic runtime variables, use the server-to-client prop pattern or runtime environment solutions.

Version Compatibility

  • Next.js 9.4+: Use NEXT_PUBLIC_ prefix (recommended)
  • Next.js 9.3 and below: Use next.config.js env configuration
  • Next.js 13+ App Router: All above solutions work, plus new runtime options

By following these patterns, you can reliably manage environment variables in Next.js applications while maintaining security and flexibility across different deployment environments.