The `use client` Directive Explained

The use client directive marks a module and everything it imports as client code. Learn what it does, where it goes, and what still runs on the server around it.

7 min read

The use client directive marks a file as the starting point for client-side rendering. It goes at the very top of a file, before any imports, and tells the bundler that this module and everything it imports should run in the browser instead of only on the server.

In the Next.js App Router, every component is a Server Component by default. Reach for use client when a component needs state, event handlers, browser APIs, or a custom hook that depends on any of those.

App.tsxApp.tsx
// app/ui/counter.tsx
"use client";
 
import { useState } from "react";
 
export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}

This button needs a click handler and local state, neither of which a Server Component can use. Import Counter into a page, and clicking the button updates the number in the browser without a full page reload.

Where the directive goes and what it marks

The directive is a plain string on its own line, placed before any import statement. Comments above it are fine, but no other code can come first.

App.tsxApp.tsx
// app/ui/search-box.tsx
"use client";
 
import { useState } from "react";
import { formatQuery } from "@/lib/format-query";
 
export default function SearchBox() {
  const [query, setQuery] = useState("");
  const onChange = (e: React.ChangeEvent<HTMLInputElement>) =>
    setQuery(formatQuery(e.target.value));
  return <input aria-label="Search" value={query} onChange={onChange} />;
}

Once this file has the directive, the format-query helper is also bundled for the client, even though that module has no directive of its own. Marking a file as client code marks that file's entire import tree as client code, not just the file itself. That is what people mean when they call it a boundary rather than a per-component flag, and it applies no matter how many plain helper functions the boundary file pulls in.

You only need it once per boundary

You do not need to repeat the directive in every file that ends up running on the client. Add it once, in the file where the client boundary starts, and every component that file imports and renders directly is treated as a Client Component from then on, with no directive of its own required.

App.tsxApp.tsx
// app/ui/gallery.tsx
"use client";
 
import { useState } from "react";
import Thumbnail from "./thumbnail";
 
export default function Gallery({ images }: { images: string[] }) {
  const [active, setActive] = useState(0);
  return <Thumbnail src={images[active]} />;
}

The thumbnail component has no directive of its own, but because gallery.tsx imports and renders it, it is still a Client Component. A plain component only becomes client code this way when a client-marked file actually reaches it through an import. If the same component were also imported separately by a Server Component elsewhere, it would render on the server in that other spot.

Server Components can still be passed in

A Client Component can accept a Server Component as children or as another prop, and that Server Component keeps rendering on the server. This works because the passed-in component is not part of the Client Component's own import tree, it is composed in from a parent Server Component instead.

App.tsxApp.tsx
// app/ui/modal.tsx
"use client";
 
import { useState } from "react";
 
export default function Modal({ children }: { children: React.ReactNode }) {
  const [open, setOpen] = useState(false);
  return (
    <div>
      <button onClick={() => setOpen(true)}>Open</button>
      {open && <div role="dialog">{children}</div>}
    </div>
  );
}

Modal only imports React and a hook, so its own bundle stays small regardless of what ends up inside it. The actual content shown in the dialog is decided by whatever the caller passes as children, not by anything modal.tsx itself imports.

App.tsxApp.tsx
// app/page.tsx
import Modal from "./ui/modal";
import Cart from "./ui/cart";
 
export default function Page() {
  return (
    <Modal>
      <Cart />
    </Modal>
  );
}

Page is a Server Component, so it renders Cart on the server and hands the finished result to Modal as children. Modal handles the open and close state on the client, while Cart still fetches its data and renders on the server, because page.tsx composes them together rather than modal.tsx importing Cart directly.

See Passing Server Components as Children to Client Components for more on this composition pattern.

What still runs on the server

A Client Component is not purely client-side. On the first request, Next.js still renders it to HTML on the server as part of the page, then sends that HTML down so the browser can show something immediately.

texttext
1. Server renders the route, including Client Components, into HTML
2. Browser shows the HTML right away
3. Browser downloads the Client Component JavaScript
4. React hydrates the HTML, attaching event handlers

After hydration, the click handlers, state, and effects in that component become active in the browser. On later client-side navigations within the app, a Client Component can render again purely in the browser, without a fresh server render producing new HTML for it.

The directive changes where a component is allowed to run, not whether the server ever touches it. This matters for performance, because a page full of Client Components still ships useful HTML on the first load instead of a blank page waiting for JavaScript.

Constraints

The directive only behaves the way described above under specific conditions, and it does not turn a file into pure client-only code in every sense.

  • It must be the first line of the file, above every import.
  • Props passed into a Client Component must be serializable, since they travel from the server render to the client. A function defined on the server cannot be passed as a prop.
  • Hooks, browser globals, and event handlers are only legal below this boundary. Using state in a file without the directive fails at build time.
  • The directive does not opt a component out of server rendering entirely. It only means the component can also run in the browser and can use client-only APIs.
  • It is unrelated to Server Functions. Marking a function with a use server directive is a different mechanism for calling server logic from the client, covered in The use server Directive Explained.

Common mistakes

The most frequent mistake is adding the directive to a file far higher in the tree than necessary, such as a whole layout, just because one small piece needs interactivity. That pulls everything the layout imports into the client bundle.

App.tsxApp.tsx
// app/layout.tsx
import Search from "./search"; // Client Component
import Logo from "./logo"; // Server Component
 
export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <div>
      <nav><Logo /><Search /></nav>
      <main>{children}</main>
    </div>
  );
}

Layout itself stays a Server Component here, since it has no directive of its own. Only search.tsx needs the directive, so Logo and the rest of the layout markup never ship as client JavaScript.

Another common mistake is passing a non-serializable value, such as a function or a class instance created on the server, into a Client Component's props. That fails because the value has to cross from a server render into browser code as plain data. Compare the two rendering models directly in Server Components vs Client Components in Next.js, and use When to Add use client and When Not To to decide where the boundary should actually sit.

Rune AI

Rune AI

Key Insights

  • use client is a React directive, not a Next.js-only feature, and it must sit above every import in the file.
  • It marks the file and its transitive imports as client code, so you do not repeat it in every component below the boundary.
  • Props passed into a Client Component must be serializable, since they cross from server to client.
  • A Client Component is still server-rendered to HTML on first load, then hydrated in the browser.
  • A Server Component passed as children or another prop into a Client Component still renders on the server, because it is not part of that file's imports.
  • use client and use server solve different problems and are not interchangeable.
RunePowered by Rune AI

Frequently Asked Questions

Is use client a Next.js feature or a React feature?

It is a React feature, defined by React itself for any framework that supports React Server Components. Next.js documents it because the App Router is built around Server Components by default.

Do I need use client on every component that uses a hook?

No. You only need it on the entry point file, the first file where client-only code starts. Every component that file imports and renders directly becomes part of the client bundle automatically.

Does use client turn off server rendering for that component?

No. A Client Component is still rendered to HTML on the server for the initial request, then hydrated in the browser. Only later client-side navigations render it purely in the browser without a server round trip.

Is use client the same as use server?

No. use client marks client-side entry points, while use server marks Server Functions that a client can call. They solve different problems and are not interchangeable.

Conclusion

The use client directive marks the file where server-only rendering ends and browser-capable code begins. Add it once at the top of an entry point file, and everything that file imports and renders directly ships to the browser, while Server Components passed in as children or props keep rendering on the server.