afaqrashid.com  ·  portfolio · 2026 ed.

"You're importing a component that needs useState" in Next.js: What It Means and the Fix

In the App Router every component is a Server Component unless its file starts with "use client". Server Components render once on the server and never run in the browser, so React hooks that hold state or react to the browser (useState, useEffect, useRouter, useContext) and createContext don't exist there. Import one into a Server Component and the build stops.

The message changed in Next.js 16

Most answers online quote the old wording: "You're importing a component that needs useState. This React Hook only works in a Client Component." On Next.js 16.4.4 the same mistake gave me this:

Error: You're importing a module that depends on `useState` into a React Server Component module.
This API is only available in Client Components. To fix, mark the file (or its parent) with the "use client" directive.

Import trace:
  Server Component:
    ./components/Counter.tsx
    ./app/page.tsx

It's the same error and the same fix. I got the identical message, with only the name swapped, for useEffect, for useRouter from next/navigation, and for createContext. With Turbopack the build listed all of them at once (five errors in my test), so one build shows every file you need to fix.

The import trace at the bottom is the useful part. The first line is the file that uses the hook, and the ones below show how a Server Component reached it. In my test a page imported a Counter component from a components folder, and the trace pointed at Counter, not the page.

Fix: "use client" on the file that uses the hook

// components/Counter.tsx
"use client";
import { useState } from "react";

export default function Counter() {
  const [n, setN] = useState(0);
  return <button onClick={() => setN(n + 1)}>{n}</button>;
}

// app/page.tsx stays a Server Component
import Counter from "@/components/Counter";

export default function Page() {
  return <Counter />;
}

That built and the page rendered the button. Put the directive at the very top of the file, before the imports, and only on the component that needs it. Adding "use client" to page.tsx also clears the error, but it turns the whole page and everything it imports into client code, and you can no longer fetch data or use server-only APIs such as cookies() directly in it.

The context trap: "use client" alone isn't enough

Context is where people get a second error after following the message. I put "use client" on the file with createContext and used <ThemeContext.Provider> in the layout, which is a Server Component. The build failed with:

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.

A Server Component only sees the exports of a client file, not properties on them, so ThemeContext.Provider is undefined on the server. Export a provider component from the client file instead:

// components/ThemeProvider.tsx
"use client";
import { createContext, useContext } from "react";

const ThemeContext = createContext("light");

export function ThemeProvider({ value, children }: { value: string; children: React.ReactNode }) {
  return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
}

export const useTheme = () => useContext(ThemeContext);

// app/layout.tsx (Server Component)
<ThemeProvider value="dark">{children}</ThemeProvider>

That built, and a client component inside it read "dark". The children you pass through the provider can still be Server Components: passing them as children doesn't make them client code.

When the hook is inside a library

  • If the trace points into node_modules, the library uses hooks but doesn't mark its files "use client". Make your own file that starts with "use client", import the component there and re-export it, then import your file instead.
  • Providers from libraries (theme, auth, data fetching, toasts) are the most common case. Wrap them all in one Providers client component and use it in the root layout.
  • If you only need a value from the request, such as a cookie or a search param, you may not need a hook at all: read it on the server with cookies() or the page's searchParams prop.

All results come from one Next.js 16.4.4 project built with next build (Turbopack) and run with next start on Node 26.

Related

Sources