Fix: React Context is unavailable in Server Components

The Symptom

You migrated to the Next.js App Router (/app directory) and attempted to wrap your root layout.tsx with a global state provider like a ThemeProvider, Redux, or Authentication Context. Instantly, the build crashes with this terminal error:

Error: createContext only works in Client Components. Add the "use client" directive at the top of the file to use it.

The Cure

If you put "use client" at the top of your root layout.tsx, you ruin all the SEO and Server-Side Rendering benefits of Next.js. Instead, you must isolate the Provider into its own client boundary file, and then import it into the server layout.

Step 1: Isolate the Client Provider

Create a separate file that strictly handles the context.

tsx (components/ThemeProvider.tsx)
"use client"; // This is the crucial boundary

import { createContext } from 'react';

// You can use createContext, useState, and useEffect safely here
export const ThemeContext = createContext({});

export default function ThemeProvider({ children }: { children: React.ReactNode }) {
  return (
    <ThemeContext.Provider value={{ theme: 'dark' }}>
      {children}
    </ThemeContext.Provider>
  );
}

Step 2: Wrap the Root Layout

Import your isolated client component into the server layout.

tsx (app/layout.tsx)
import ThemeProvider from '@/components/ThemeProvider';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  // Notice there is NO "use client" here. 
  // This layout stays a Server Component for maximum SEO and performance.
  return (
    <html lang="en">
      <body>
        <ThemeProvider>
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

The Breakdown

In the Next.js App Router, every component is a Server Component by default. Server Components are rendered on the backend (Node/Edge). Because React Context relies on continuous state and interactive re-renders happening inside the user's browser, the server has no way to process it.

If you try to call createContext() inside a Server Component, React instantly throws an error. The "Boundary Pattern" (shown in the cure) solves this by separating the concerns:

A Note on "children"

You might wonder: "If I wrap everything in a Client Component, doesn't that turn the entire app into a Client Component?"

No. In React, passing components via the {children} prop allows Server Components to bypass the Client boundary. Your page contents passed inside <ThemeProvider> will still be securely rendered on the server.

Developer Logs

Loading logs...