Why Your Next.js 15 Cookies Work Locally But Break in Production (And How to Fix It)

You've spent hours setting up authentication in your Next.js application. Everything works perfectly in your local development environment - users can log in, sessions persist, and protected routes work as expected. But then you deploy to production, and suddenly everything breaks. Users are stuck on the login page, and your server components can't seem to read any cookies, even though you can see them in the browser's dev tools.

If this sounds familiar, you're not alone. Cookie management in Next.js 15, especially in production environments, can be surprisingly tricky. In this comprehensive guide, we'll dive into why these issues occur and how to fix them.

The most common scenario goes something like this:

  1. Your Express.js backend sets an authentication cookie

  2. The cookie shows up perfectly in your local development environment

  3. After deployment, the cookie appears in request headers but returns undefined when accessed via Next.js's cookies() function

  4. Your authentication system breaks, leaving users unable to access the application

This frustrating situation often stems from subtle differences between development and production environments, combined with Next.js 15's unique approach to cookie management.

Why Cookies Behave Differently in Production

Several factors can cause cookies to break in production while working perfectly in development:

In development (localhost), cookies marked as secure will work over HTTP. However, in production, these same cookies will be rejected unless your site is served over HTTPS. This is a common gotcha that catches many developers off guard.

// This works locally but fails in production without HTTPS
res.cookie('sessionId', 'abc123', {
  secure: true,  // Requires HTTPS in production
  httpOnly: true
});

2. Domain Restrictions

Cookies are domain-scoped, which means they follow strict rules about which domains can set and access them. Your local development server might be more permissive than your production environment when it comes to cross-domain cookie handling.

// Example of domain-specific cookie setting
res.cookie('authToken', token, {
  domain: process.env.NODE_ENV === 'production' 
    ? '.yourdomain.com'
    : 'localhost'
});

3. CORS Configuration Mismatches

When your frontend and backend are on different origins, CORS settings become crucial. A common issue occurs when the CORS configuration doesn't properly handle credentials:

// Backend CORS configuration
app.use(cors({
  origin: process.env.FRONTEND_URL,
  credentials: true  // Essential for cookie handling
}));

// Frontend fetch configuration
fetch('https://api.yourdomain.com/auth', {
  credentials: 'include'  // Required for cross-origin cookie transmission
});

Let's walk through a systematic approach to diagnose and fix cookie problems in production.

First, check if your cookies are actually being sent in the request headers:

// In your middleware.ts
export default function middleware(req: NextRequest) {
  console.log('Cookie Header:', req.headers.get('cookie'));
  console.log('All Headers:', Object.fromEntries(req.headers));
  
  return NextResponse.next();
}

Review your cookie configuration to ensure all required attributes are set correctly:

// Proper cookie configuration
res.cookie('sessionId', token, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'lax',
  path: '/',
  maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
});

3. Check Server Component Implementation

Ensure you're properly accessing cookies in your Server Components:

// Correct way to access cookies in a Server Component
import { cookies } from 'next/headers';

async function ServerComponent() {
  const cookieStore = cookies();
  const authToken = cookieStore.get('authToken');
  
  if (!authToken) {
    // Handle unauthenticated state
    return <div>Please log in</div>;
  }
  
  // Continue with authenticated content
}

Common Solutions and Best Practices

When setting cookies from API routes, use the Next.js Response object correctly:

import { NextResponse } from 'next/server';

export async function POST(request) {
  const response = NextResponse.json({ success: true });
  
  response.cookies.set('authToken', token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    path: '/'
  });
  
  return response;
}

2. Environment-Specific Configuration

Create environment-specific cookie configurations to handle different requirements:

// config/cookie-options.ts
export const getCookieOptions = () => ({
  secure: process.env.NODE_ENV === 'production',
  domain: process.env.NODE_ENV === 'production' 
    ? process.env.COOKIE_DOMAIN 
    : 'localhost',
  sameSite: process.env.NODE_ENV === 'production' ? 'strict' : 'lax',
  httpOnly: true
});

3. Implementing Fallback Mechanisms

When cookies aren't accessible, implement fallback mechanisms to maintain functionality:

async function getAuthStatus() {
  try {
    // Try cookies first
    const cookieStore = cookies();
    const authToken = cookieStore.get('authToken');
    
    if (authToken) return authToken;
    
    // Fallback to Authorization header
    const headers = new Headers();
    const authHeader = headers.get('Authorization');
    
    return authHeader?.replace('Bearer ', '');
  } catch (error) {
    console.error('Auth verification failed:', error);
    return null;
  }
}

Production Deployment Checklist

Before deploying your Next.js application, run through this checklist to prevent cookie-related issues:

  1. HTTPS Configuration

    • Ensure your production domain has valid SSL certificates

    • Configure your server to redirect HTTP to HTTPS

    • Verify cookie secure flag is enabled for production

  2. Domain Configuration

    • Verify cookie domains match your production setup

    • Check subdomain handling if applicable

    • Ensure proper CORS configuration for cross-origin requests

  3. Cookie Attributes

    • Review sameSite attribute settings

    • Confirm httpOnly is set for sensitive cookies

    • Verify path attribute is correctly configured

  4. Error Handling

    • Implement proper error handling for cookie access failures

    • Add logging for debugging cookie issues in production

    • Set up monitoring for authentication-related errors

Conclusion

Cookie management in Next.js 15, particularly in production environments, requires careful attention to detail and understanding of how different environments handle cookie security. By following the debugging steps and implementing the solutions outlined in this guide, you can ensure your cookies work consistently across all environments.

Remember these key takeaways:

  • Always test cookie functionality in a production-like environment before deployment

  • Implement proper CORS and security configurations

  • Use environment-specific settings for cookie attributes

  • Add comprehensive error handling and logging

For more information and updates, refer to the official Next.js documentation and stay tuned to the Next.js GitHub discussions for community solutions to common issues.

By following these guidelines and best practices, you can avoid the frustration of cookies that work locally but break in production, ensuring a smooth user experience across all environments.

Raymond Yeh

Raymond Yeh

Published on 20 March 2025

Get engineers' time back from marketing!

Don't let managing a blog on your site get in the way of your core product.

Wisp empowers your marketing team to create and manage content on your website without consuming more engineering hours.

Get started in few lines of codes.

Choosing a CMS
Related Posts
How to Handle Authentication Across Separate Backend and Frontend for Next.js Website

How to Handle Authentication Across Separate Backend and Frontend for Next.js Website

Learn how to implement secure authentication in Next.js with Express backend using httpOnly cookies, JWT tokens, and middleware. Complete guide with code examples.

Read Full Story
Handling Common CORS Errors in Next.js 15

Handling Common CORS Errors in Next.js 15

Tired of seeing "Access to fetch at... has been blocked by CORS policy" errors? Dive into our guide to master CORS issues in Next.js and streamline your development process.

Read Full Story
How to Use Next.js as a Front-End Framework: A Complete Authentication Guide with Nest.js

How to Use Next.js as a Front-End Framework: A Complete Authentication Guide with Nest.js

Learn secure Next.js authentication with Nest.js: Implement JWT tokens, httpOnly cookies, and token rotation. Complete guide with code examples for frontend-only Next.js apps.

Read Full Story
Loading...