Server vs Client Components
When you need 'use client' and how data crosses the boundary.
Updated
What Server Components and Client Components are
In Next.js, every component runs either on the server or in the browser (and on the server, for the first render). The choice decides what the component can do and how much JavaScript reaches the user.
- Server Component — runs only on the server. Its code never reaches the browser; the user only receives the resulting HTML.
- Client Component — is sent to the browser as JavaScript, gets hydrated and can be interactive.
In app/, every component is a Server Component by default. It becomes a Client Component when the file starts with 'use client'.
The differences
| Server Component | Client Component | |
|---|---|---|
| Runs | only on the server | the server (initial HTML) + the browser |
| JS sent to the browser | zero | the component's code + its dependencies |
async / await directly |
yes | no |
| Access to the DB, files, secrets | yes | no |
useState, useEffect, hooks |
no | yes |
onClick, onChange |
no | yes |
window, localStorage |
no | yes |
When to use each
| You need... | Choice |
|---|---|
| to read data (a DB, an API) and display it | Server |
| static content: text, layout, lists | Server |
| secrets (API keys, the DB URL) | Server |
| state, effects, event handlers | Client |
| browser APIs (localStorage, geolocation) | Client |
| libraries that use hooks (charts, editors) | Client |
// a Server Component — the default
export default async function Page() {
const posts = await db.post.findMany()
return <PostList posts={posts} />
}'use client'
import { useState } from 'react'
export function LikeButton({ initial }: { initial: number }) {
const [likes, setLikes] = useState(initial)
return <button onClick={() => setLikes(likes + 1)}>♥ {likes}</button>
}The golden rule
Keep 'use client' as low as possible in the tree. The page stays on the server; only the interactive button is a client one. 'use client' marks a boundary: the file and everything it imports become client code.
PageserverHeaderserverPostListserverLikeButtonclient — only this reaches the browser as JS
Footerserver
The server → client boundary
| Rule | Details |
|---|---|
| Data crosses through props | it must be serializable: strings, numbers, plain objects, arrays, Dates, Promises |
| No functions as props | the exception: Server Actions |
A Client Component can receive Server Components as children |
<ClientModal><ServerContent /></ClientModal> |
| A Client Component can't import a Server Component | it only receives it as children / a prop |
Server Actions — mutations from the client
'use server' functions you call from the client, but that run on the server — for forms and mutations. The Server Actions lesson.
Summary
- A Server Component (the default): async, access to data and secrets, zero JS in the browser.
- A Client Component (
'use client'): state, effects, events, browser APIs. 'use client'as low as possible; serializable props across the boundary.