How to fix cookies() can only be called in a Server Component in React

ReactINTERMEDIATEMEDIUMUpdated Dec 8, 2025ยท 169 views

This error occurs when attempting to use Next.js's cookies() function inside a Client Component marked with "use client". The cookies() API is designed exclusively for Server Components, Server Actions, and Route Handlers where HTTP headers can be properly accessed.

Quick fix

Fixes cookies() can only be called in a Server Component

// app/components/UserProfile.tsx (Server Component - no "use client")
import { cookies } from 'next/headers';
import ClientDisplay from './ClientDisplay';

export default async function UserProfile() {
  const cookieStore = await cookies();
  const token = cookieStore.get('auth-token');
  
  return <ClientDisplay token={token?.value} />;
}

// app/components/ClientDisplay.tsx (Client Component)
'use client';

export default function ClientDisplay({ token }: { token?: string }) {
  // Use token in client-side logic
  return <div>Token: {token}</div>;
}
  1. Move cookie logic to a Server Component
  2. Use Server Actions for cookie operations
  3. Create a Route Handler for cookie access
  4. Use client-side cookie libraries for non-sensitive data
react โ€” error
// app/components/UserProfile.tsx (Server Component - no "use client")
import { cookies } from 'next/headers';
import ClientDisplay from './ClientDisplay';
export default async function UserProfile() {
const cookieStore = await cookies();
const token = cookieStore.get('auth-token');
return <ClientDisplay token={token?.value} />;
}
// app/components/ClientDisplay.tsx (Client Component)
'use client';
export default function ClientDisplay({ token }: { token?: string }) {
// Use token in client-side logic
return <div>Token: {token}</div>;
}
cookies() can only be called in a Server Component

What this error means

This error indicates you're trying to call the Next.js cookies() function from next/headers within a Client Component. The cookies() function is part of Next.js's server-side API that accesses HTTP request cookies during server-side rendering. Client Components execute in the browser where direct access to HTTP headers is not available for security reasons. The cookies() function can read incoming request cookies in Server Components and read/write cookies in Server Actions or Route Handlers. When you mark a component with "use client", it becomes a Client Component that hydrates on the browser side, where the cookies() function cannot operate because it requires access to the HTTP request/response cycle that only exists on the server. This restriction is intentional in Next.js's architecture to maintain a clear separation between server and client execution contexts. Cookies contain sensitive authentication tokens and session data that should be handled securely on the server side, not exposed to client-side JavaScript unless explicitly intended.

Typical symptoms

  • Runtime error stating "cookies() can only be called in a Server Component" when component renders
  • Application crashes or fails to hydrate when accessing cookies in a "use client" component
  • Build succeeds but runtime error occurs when the component tries to execute cookies()
  • Error appears in browser console or Next.js development overlay
  • Component worked fine as Server Component but broke after adding "use client" directive
  • Authentication or session logic fails because cookie data is unavailable
  • Similar errors with headers() or other next/headers functions in Client Components

Common causes

  1. Directly importing and calling cookies() from next/headers in a component marked with "use client"
  2. Converting a Server Component that uses cookies() to a Client Component without refactoring cookie access
  3. Attempting to read authentication tokens or session cookies in client-side event handlers
  4. Misunderstanding Next.js App Router architecture where Server and Client Components have different capabilities
  5. Trying to access cookies in useEffect or other React hooks within a Client Component
  6. Using cookies() in a component that needs interactivity (onClick, useState) and was made client-side
  7. Third-party components or libraries that call cookies() being imported into Client Components
  8. Not realizing that Server Components are the default and cookies() only works server-side

How to fix "cookies() can only be called in a Server Component"

1Move cookie logic to a Server Component

The simplest solution is to keep cookie access in Server Components and pass the data as props to Client Components:

typescript
// app/components/UserProfile.tsx (Server Component - no "use client")
import { cookies } from 'next/headers';
import ClientDisplay from './ClientDisplay';

export default async function UserProfile() {
  const cookieStore = await cookies();
  const token = cookieStore.get('auth-token');
  
  return <ClientDisplay token={token?.value} />;
}

// app/components/ClientDisplay.tsx (Client Component)
'use client';

export default function ClientDisplay({ token }: { token?: string }) {
  // Use token in client-side logic
  return <div>Token: {token}</div>;
}

This maintains the security boundary while allowing interactivity in the Client Component.

2Use Server Actions for cookie operations

If you need to set or modify cookies from client-side interactions, create a Server Action:

typescript
// app/actions/auth.ts
'use server';
import { cookies } from 'next/headers';

export async function setAuthToken(token: string) {
  const cookieStore = await cookies();
  cookieStore.set('auth-token', token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    maxAge: 60 * 60 * 24 * 7 // 1 week
  });
}

// app/components/LoginButton.tsx
'use client';
import { setAuthToken } from '../actions/auth';

export default function LoginButton() {
  async function handleLogin() {
    const token = await fetchToken();
    await setAuthToken(token);
  }
  
  return <button onClick={handleLogin}>Login</button>;
}

Server Actions allow safe cookie modification from client interactions.

3Create a Route Handler for cookie access

For more complex cookie operations, use a Route Handler:

typescript
// app/api/auth/route.ts
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';

export async function GET() {
  const cookieStore = await cookies();
  const token = cookieStore.get('auth-token');
  
  return NextResponse.json({ token: token?.value });
}

export async function POST(request: Request) {
  const { token } = await request.json();
  const cookieStore = await cookies();
  
  cookieStore.set('auth-token', token, {
    httpOnly: true,
    secure: true,
    sameSite: 'strict'
  });
  
  return NextResponse.json({ success: true });
}

// app/components/ClientComponent.tsx
'use client';
import { useEffect, useState } from 'react';

export default function ClientComponent() {
  const [token, setToken] = useState<string | null>(null);
  
  useEffect(() => {
    fetch('/api/auth')
      .then(res => res.json())
      .then(data => setToken(data.token));
  }, []);
  
  return <div>Token: {token}</div>;
}

This provides a clean API boundary for client-server cookie communication.

4Use client-side cookie libraries for non-sensitive data

For client-side cookies that don't require server-side security (like UI preferences), use a client-safe library:

bash
npm install js-cookie
# or
npm install cookies-next
typescript
// app/components/ThemeToggle.tsx
'use client';
import Cookies from 'js-cookie';
import { useState } from 'react';

export default function ThemeToggle() {
  const [theme, setTheme] = useState(() => Cookies.get('theme') || 'light');
  
  function toggleTheme() {
    const newTheme = theme === 'light' ? 'dark' : 'light';
    Cookies.set('theme', newTheme, { expires: 365 });
    setTheme(newTheme);
  }
  
  return <button onClick={toggleTheme}>{theme} mode</button>;
}

IMPORTANT: Never store sensitive data (auth tokens, session IDs) in client-accessible cookies without httpOnly flag.

5Pass cookie data through page props

For page-level cookie access, read cookies in the page Server Component and pass to children:

typescript
// app/dashboard/page.tsx
import { cookies } from 'next/headers';
import DashboardClient from './DashboardClient';

export default async function DashboardPage() {
  const cookieStore = await cookies();
  const userPrefs = cookieStore.get('preferences')?.value;
  const sessionId = cookieStore.get('session')?.value;
  
  return (
    <DashboardClient 
      preferences={userPrefs ? JSON.parse(userPrefs) : null}
      hasSession={!!sessionId}
    />
  );
}

// app/dashboard/DashboardClient.tsx
'use client';

interface Props {
  preferences: any;
  hasSession: boolean;
}

export default function DashboardClient({ preferences, hasSession }: Props) {
  // Client component can use the data without accessing cookies directly
  return <div>{hasSession ? 'Logged in' : 'Guest'}</div>;
}

This pattern keeps cookie access server-side while enabling full client interactivity.

6Verify component boundaries are correctly set

Check that you haven't accidentally added "use client" where it's not needed:

typescript
// BAD: Unnecessary "use client" prevents cookies() usage
'use client'; // Remove this if you don't need interactivity
import { cookies } from 'next/headers';

export default async function ServerComponent() {
  const cookieStore = await cookies(); // This will error
  // ...
}

// GOOD: Server Component (default)
import { cookies } from 'next/headers';

export default async function ServerComponent() {
  const cookieStore = await cookies(); // This works
  // ...
}

Remember: Server Components are the default in Next.js App Router. Only add "use client" when you need browser APIs, React hooks, or event handlers.

Advanced notes

When designing your Next.js application architecture, follow the principle of reading cookies as high up in the component tree as possible (preferably in layout.tsx or page.tsx Server Components) and passing the data down as props. This minimizes the surface area where sensitive cookie data exists and makes security audits easier.

For authentication patterns, consider using Next.js middleware (middleware.ts) to validate cookies before requests reach your components. Middleware can read and modify cookies for all routes, providing a centralized authentication layer.

Be aware that passing cookie values as props to Client Components serializes them into the HTML, making them visible in the browser's page source. Only pass non-sensitive data or identifiers, never raw authentication tokens or session secrets. For sensitive operations, always use Server Actions or Route Handlers.

The cookies() function is async in Next.js 15+, so always await it: const cookieStore = await cookies(). In earlier versions, it was synchronous. Check your Next.js version if you encounter async-related errors.

If you're migrating from Pages Router to App Router, note that getServerSideProps patterns need to be refactored into Server Components or Server Actions. The cookies API works differently between the two routing paradigms.

For testing, mock the cookies() function in your test environment since it only works in Next.js server contexts. Use libraries like next-test-api-route-handler for integration testing Route Handlers that use cookies.

Frequently asked questions

What does "cookies() can only be called in a Server Component" mean?
js cookies() function from next/headers within a Client Component. js's server-side API that accesses HTTP request cookies during server-side rendering. Client Components execute in the browser where direct access to HTTP headers is not available for security reasons.
How do I fix "cookies() can only be called in a Server Component"?
This error occurs when attempting to use Next.js's cookies() function inside a Client Component marked with "use client". The cookies() API is designed exclusively for Server Components, Server Actions, and Route Handlers where HTTP headers can be properly accessed.
What causes "cookies() can only be called in a Server Component"?
Directly importing and calling cookies() from next/headers in a component marked with "use client" Converting a Server Component that uses cookies() to a Client Component without refactoring cookie access Attempting to read authentication tokens or session cookies in client-side event handlers
Is the "cookies() can only be called in a Server Component" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading