'use client'
Declares a module as a client entry point so its components render with browser JavaScript.
'use client'- Added in Next.js v13.0.0
Errors
Importing a server-only module — one that uses next/headers or is marked with the server-only package — from a 'use client' module is a build error.
Changelog
- PHP v13.4.0App Router and the server/client boundary became stable.
- PHP v13.0.0Directive introduced with the App Router and React Server Components.
'use client' declares the entry point where the server module graph hands off to the client one. Everything the file imports, transitively, joins the client bundle. Reach for it when a component needs state, effects, event handlers, or a browser API such as window or localStorage.
Placement
It must be the very first line of the file, before any imports. It is module-wide: there is no way to mark one function in a shared file as client-only. You do not need it on every file that ends up in the browser — only on the files whose components are rendered directly by a Server Component. Everything imported from there is already on the client side of the boundary.
What trips people up
Props crossing the boundary must be serializable. Passing an onClick function down from a Server Component is the classic failure; a reference to a Server Function is the one function-shaped value that does cross. Marking a page 'use client' to fix one button pulls the whole subtree client-side, so push the directive down to the smallest interactive leaf instead, and pass server-rendered markup in through children.
Example
'use client'
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
)
}When to use it
- Add a counter, tab switcher, or modal that needs useState.
- Read localStorage or window.matchMedia on mount.
- Render a form that uses useActionState to display validation errors.
Frequently asked questions
Where exactly does 'use client' go in the file?
On the very first line, above every import — a directive placed after an import is ignored and the module stays a Server Component. It must also be a plain string literal, so a comment or a blank line above it is fine but any statement is not.
Do I have to add 'use client' to every component in my app?
No — only to the files whose components a Server Component renders directly. Anything those files import is already part of the client graph, so repeating the directive down the tree changes nothing.
Why do I get "Event handlers cannot be passed to Client Component props"?
A Server Component tried to pass a function such as onClick across the boundary, and functions are not serializable. Define the handler inside the Client Component, or pass a Server Function reference if the work belongs on the server.
More examples
Keeping the boundary at the leaf
Only `counter.tsx` carries the directive, so `getStats` and `Header` never ship to the browser. Moving `'use client'` to the top of `page.tsx` instead would compile the whole page — and its data-fetching imports — for the client, which is the most common cause of a bundle jumping in size.
// app/page.tsx — no directive, stays a Server Component
import Header from './header'
import Counter from './counter' // This is a Client Component
export default async function Page() {
const stats = await getStats() // runs on the server only
return (
<div>
<Header />
<p>Total: {stats.total}</p>
<Counter />
</div>
)
}Which props can and cannot cross
React serializes props when it sends them from server to client, so plain objects, arrays, strings, numbers, and dates pass through while functions and class instances do not. A Server Function is the exception: what crosses is its encrypted action ID, not the code.
// app/components/counter.tsx
'use client'
export default function Counter({
label, // string — serializable
start, // number — serializable
action, // Server Function reference — the one function-shaped value that crosses
}: {
label: string
start: number
action: (formData: FormData) => Promise<void>
}) {
return (
<form action={action}>
<input type="hidden" name="start" value={start} />
<button type="submit">{label}</button>
</form>
)
}
// A plain function prop is NOT serializable: passing
// onClick={() => {}} from a Server Component throws
// "Event handlers cannot be passed to Client Component props".
// app/page.tsx
import Counter from './components/counter'
import { updateCount } from './actions'
export default function Page() {
return <Counter label="Add" start={0} action={updateCount} />
}Server-rendered children inside a Client Component
`children` arrives already rendered on the server, so a Client Component can hold interactive state around server-only content. This is how you keep a heavy chart or database-backed subtree out of the browser bundle even though a client wrapper controls its visibility.
// app/components/panel.tsx
'use client'
import { useState, type ReactNode } from 'react'
export function Panel({ children }: { children: ReactNode }) {
const [open, setOpen] = useState(false)
return (
<div>
<button onClick={() => setOpen(!open)}>Toggle</button>
{open ? children : null}
</div>
)
}
// app/page.tsx — ServerChart never enters the client bundle
import { Panel } from './components/panel'
import { ServerChart } from './server-chart'
export default function Page() {
return (
<Panel>
<ServerChart />
</Panel>
)
}
Discussion