Technology · Next.js

Next.js Environment Variables

Manage environment variables and configure Next.js for different environments.

TL;DR
  1. 01Use .env.local for environment variables in development.
  2. 02Variables prefixed NEXT_PUBLIC_ are exposed to browser.
  3. 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.

Next.js DirectivesNext.js Error Handling