use client vs use server in Next.js: The Real Difference
The #1 misconception in the App Router: "use server" is not the opposite of "use client". One marks a client boundary in the module graph; the other exposes callable server functions. Server Components are the default — no directive needed.
If you think "use client" and "use server" are opposites — one for client components, one for server components — you have the single most common App Router misconception. They are not symmetric. This guide nails down what each actually does, straight from the React and Next.js docs.
Server Components are the default#
In the App Router, "by default, layouts and pages are Server Components." An unmarked file in app/ is already a Server Component — there is no directive to "make" one. Keep this in mind; it's why "use server" can't be the way to create one.
What "use client" does#
"use client" marks the boundary in the module dependency tree where code switches from server to client. From the React docs: it marks "the module and its transitive dependencies as client code" and defines the boundary "on the module dependency tree, not the render tree."
// 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}</button>
}The crucial nuance most people miss: the boundary follows imports, not props. A Server Component passed as children to a Client Component stays a Server Component — it's rendered on the server and passed in as output. Only imported descendants get pulled client-side.
The directive must be at the very top of the file, above imports (comments are fine), with single or double quotes — not backticks.
What "use server" does (the misconception)#
"use server" marks Server Functions (a.k.a. Server Actions) — async functions that run on the server but are callable from client code. The React docs: it "marks server-side functions that can be called from client-side code." It does not make a component a Server Component.
// app/actions.ts
'use server'
import { db } from '@/lib/db'
export async function archiveInactiveUsers() {
// runs on the server, callable from the client
await db.user.updateMany({ where: { active: false }, data: { archived: true } })
}// app/components/archive-button.tsx
'use client'
import { useTransition } from 'react'
import { archiveInactiveUsers } from '../actions'
export default function ArchiveButton() {
const [isPending, startTransition] = useTransition()
return (
<button
disabled={isPending}
onClick={() => startTransition(() => archiveInactiveUsers())}
>
Archive inactive users
</button>
)
}The example is a mutation, not a read, on purpose. The React docs state that Server Functions "are designed for mutations that update server-side state; they are not recommended for data fetching", and that outside a <form action> they "should be called in a Transition". To load data, fetch it in a Server Component and pass it down as props.
It has two legal placements: at the top of a file (marks all exports as Server Functions) or inline at the top of an async function body (marks just that function). It cannot go on a non-async function.
The contrast, side by side#
"use client" | "use server" | |
|---|---|---|
| Goes | Top of a file, above imports | Top of a file, or inline in an async function |
| Marks | A boundary: this module + imports become client code | Server Functions callable from the client |
| Acts on | The module import graph | Individual server functions |
| Common mistake | Placed too high → whole subtree ships to client | Used hoping to "force a Server Component" |
The two classic mistakes#
The Next.js docs spell out the second fix: "add 'use client' at the top of the files that define your interactive components instead of marking large parts of your UI as Client Components."
"Server Actions" was the original name; React/Next now use "Server Functions" as the umbrella term, with "Server Actions" meaning ones wired to forms / action props. If you're searching docs, both terms point at the same "use server" feature.
- This is App Router only — the Pages Router has neither directive nor Server Components.
- Some bundlers strip
"use client"when building component libraries; library authors need bundler config to preserve it. - Both directives are an RSC-era (React 19) feature — they don't apply to a classic React 18 SPA.
Official references: React use client, React use server, Next.js Server and Client Components.
What can actually cross the boundary as a prop#
The article above explains that a Server Component passed as children stays server-
rendered. The nuance it doesn't cover: when a Server Component passes a regular prop
(not children) down into a "use client" component, that prop has to survive being
serialized across the server/client boundary, and not everything can.
Plain objects, arrays, strings, numbers, and booleans cross fine. Functions generally
don't — a function defined in a Server Component has no way to run in the browser,
so passing one as a prop to a Client Component throws at build or render time, not
silently. The one deliberate exception is a Server Function created with "use server":
those are serialized as a special reference the client can call back into, which is
exactly the mechanism the "use server" half of this article's examples relies on. Plain
event handlers or arbitrary closures don't get that treatment — only functions actually
marked as Server Functions do.
// app/page.tsx — Server Component
import ClientButton from './client-button'
export default function Page() {
const onClick = () => console.log('this never runs in the browser')
// ❌ passing a plain function this way fails — it isn't a Server Function
return <ClientButton onClick={onClick} />
}This is the same failure whether the function is inline, imported, or a method on an
object you're passing down — if it isn't behind "use server", it isn't callable on
the client. Event handlers cannot be passed to Client Component props — fix
walks through the exact error message this produces and the two real fixes: move the
handler into the Client Component itself, or turn it into a proper Server Function.
Context providers have to be Client Components — which forces a file split#
The Next.js docs are blunt about it: "React context is not supported in Server
Components." So any <ThemeProvider>, <AuthProvider>, or other
context provider in an App Router project has to be a "use client" component.
The trap this article's examples don't show: putting "use client" directly on the
file that also defines your root layout content pulls that entire file's imports into
the client bundle — the same "boundary follows imports, not just the one component you
meant to mark" problem covered above, just with a provider as the culprit this time
instead of a <Counter />.
The fix is a dedicated wrapper file that does nothing except hold the directive and the provider:
// app/providers.tsx
'use client'
import { createContext } from 'react'
export const ThemeContext = createContext('light')
export default function Providers({ children }: { children: React.ReactNode }) {
return <ThemeContext.Provider value="light">{children}</ThemeContext.Provider>
}// app/layout.tsx — stays a Server Component
import Providers from './providers'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}RootLayout itself never gets the directive, so everything it imports besides
Providers — and everything passed to it as children — stays server-rendered exactly
as described in the deep dive on
React Server Components: only the provider
file crosses the boundary, not the whole tree it wraps.
Further reading: useSearchParams Suspense Error: 3 Real Fixes (Next.js 15). Also see Fix Unsupported Server Component type: undefined. Also see Unrecognized feature: 'interest-cohort' on GitHub Pages.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
Continue Reading
Fix localStorage is not defined after 'use client' (Next.js)
The cookie banner from the Stack Overflow question, rebuilt on Next.js 16.3.8: why 'use client' does not stop the crash, the useEffect fix, and the other errors Node 25 and 26 print.
Fix Unsupported Server Component type: undefined
Keep the page on the server while repairing Container.Window: direct named imports work, and changing to a default export alone does not fix this case.
Fix Functions cannot be passed directly to Client Components
Read the caret line to find the exact prop, then keep that function on the client side of the boundary: four reproduced shapes on Next.js 16.4.0, and why "use server" rarely fixes it.


