I created a ThemeContext with createContext in a file used by app/layout.tsx and Next says: 'You're importing a component that needs createContext. It only works in a Client Component'. How should I structure providers?
DEV3 Developer Forum
Why do I get 'createContext only works in Client Components' in Next.js?
Ask a question
Every post is reviewed first. Usually reviewed within 24 hours.
dev3 ·
0
1 reply
dev3 · Accepted answer
Context needs React state at runtime, which server components do not have. Put the provider in its own client component and render it inside the (server) layout.
// app/providers.tsx
"use client";
import { createContext, useContext, useState } from "react";
const ThemeCtx = createContext<{ dark: boolean; toggle: () => void } | null>(null);
export function Providers({ children }: { children: React.ReactNode }) {
const [dark, setDark] = useState(false);
return (
<ThemeCtx.Provider value={{ dark, toggle: () => setDark((d) => !d) }}>
{children}
</ThemeCtx.Provider>
);
}
export function useTheme() {
const ctx = useContext(ThemeCtx);
if (!ctx) throw new Error("useTheme must be used inside <Providers>");
return ctx;
}
// app/layout.tsx (server component)
import { Providers } from "./providers";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
Why this works
children passed into a client component can still be server components, because they are rendered on the server first and passed through as already-rendered output. So wrapping the whole app in a provider does not turn the pages into client code.
Tips
- Keep providers as deep as practical and combine several in one
Providerscomponent. - Libraries that use context (React Query, theme libraries, MUI) need the same wrapper.
- Do not share request-specific data via a module-level variable on the server: different users share the module. Use props,
cache()or headers.
Pitfall: any file that imports a hook such as useState or useContext must be a client component, including small helpers, or you hit the same error in a different file.
0