In the Next.js App Router, pages and layouts are Server Components by default. Add "use client" only when a component needs state, event handlers, effects, browser APIs, or client-side context. The goal is not to make everything server-only. The goal is to keep the client boundary as small and intentional as possible.
Quick decision table
| Need | Server Component | Client Component |
|---|---|---|
| Read a database or server secret directly | Yes | No |
| Fetch public content on the server | Yes | Sometimes, but often unnecessary |
Use useState or useReducer |
No | Yes |
Use onClick or onChange |
No | Yes |
Use useEffect or window |
No | Yes |
| Reduce JavaScript sent to the browser | Yes | No |
Start server-side, then move only interactive leaf components to the client.
Default Server Components
// app/blog/page.tsx
export default async function BlogPage() {
const posts = await getPosts()
return (
<main>
<h1>Blog</h1>
<PostList posts={posts} />
</main>
)
}
A Server Component can read server-side data without shipping its implementation as interactive JavaScript. It cannot use event handlers, state, effects, or browser globals.
Keep "use client" narrow
If only a search box is interactive, mark only the search box:
// components/SearchBox.tsx
"use client"
import { useState } from "react"
export function SearchBox() {
const [query, setQuery] = useState("")
return <input value={query} onChange={(event) => setQuery(event.target.value)} />
}
The page can remain a Server Component:
import { SearchBox } from "@/components/SearchBox"
export default async function BlogPage() {
const posts = await getPosts()
return (
<>
<SearchBox />
<PostList posts={posts} />
</>
)
}
"use client" defines a module graph boundary. The file and the dependencies it imports become part of the client module graph. Avoid placing it at the top of a large page or root layout just to support one button.
Server UI can be passed into Client UI
Client Components can receive already-rendered server UI through children:
// components/Modal.tsx
"use client"
export function Modal({ children }: { children: React.ReactNode }) {
return <dialog>{children}</dialog>
}
<Modal>
<ServerRenderedArticle />
</Modal>
Do not import server-only modules directly into a Client Component file. Compose them from a Server Component parent instead.
Props must be serializable
Data crossing from a Server Component to a Client Component must be serializable. Plain objects, arrays, strings, numbers, and booleans are usually fine. Database connections, class instances, arbitrary functions, and complex runtime objects are not.
Dates should be converted deliberately, usually to strings, then formatted with clear timezone behavior. Otherwise the server and browser may render different initial output.
What happens on first load
Next.js renders Server Components on the server and produces the React Server Component payload. The browser receives HTML for the initial view, then hydrates Client Components with JavaScript so they become interactive.
This means Client Components may still be pre-rendered into initial HTML. "Client Component" does not mean "only rendered in the browser." If the server render and the first browser render differ, you can still get a hydration mismatch. For debugging, see React Hydration Failed: Causes, Debugging, and Fixes.
Common mistakes
- Adding
"use client"to an entire page for a single interactive control. - Reading
windowin a Server Component. - Passing private environment variables into browser code.
- Passing non-serializable objects across the server-client boundary.
- Refetching first-screen data in
useEffectwhen the server could fetch it directly. - Using
typeof windowto render different initial JSX.
Recommended structure
Server Page
├── Server Header
├── Server ArticleList
│ └── Client FavoriteButton
└── Client SearchPanel
└── Initial data from the server
Move client boundaries up only when multiple interactive components truly need shared client state.
Related FreeMac guides
- For route structure, read Next.js Routing Guide: App Router Patterns.
- For images inside App Router pages, see Next.js Image Guide: sizes, fill, and Remote Images.
- For choosing Server Actions or fetch, read Next.js Server Actions vs Fetch: How to Choose.
Continue reading
Next.js Routing Guide: App Router Patterns
Learn the current Next.js App Router model: static routes, dynamic segments, catch-all routes, layouts, route groups, parallel routes, and route handlers.
9 minReact Hydration Failed: Causes, Debugging, and Fixes
Debug server and client rendering mismatches caused by dates, random values, browser APIs, invalid HTML, local storage, locale differences, and DOM-changing extensions.
11 min readNext.js Image Guide: sizes, fill, and Remote Images
Use the modern Next.js Image component with width and height, fill, sizes, preload, placeholders, remotePatterns, and clear rules for avoiding outdated layout props.
Subscribe to FreeMac
Weekly picks: free Mac software reviews, trusted source updates, alternatives, and low-friction guides.