React Server Components: When to Reach for the Client
A mental model for the server/client boundary in the Next.js App Router — what runs where, why it matters, and how to ship less JavaScript.

The biggest shift in the Next.js App Router isn't the file structure — it's that components are server components by default. Get the mental model right and you ship faster sites with less code. Get it wrong and you fight the framework all day.
The default is the server
Every component is a server component unless you opt out. Server components:
- Run only at build or request time — their code never reaches the browser.
- Can be
asyncand fetch data directly. - Can't use hooks, state, effects, or browser APIs.
That last point isn't a limitation; it's the whole benefit. Code that doesn't need the browser doesn't get sent to it.
"use client" marks a boundary, not a file
The directive doesn't just make one component interactive — it marks the start of a client subtree. Everything imported into a client component travels to the browser too. So push the directive as far down the tree as you can.
// page.tsx — server component, no JS shipped
export default async function Page() {
const posts = await getPosts();
return (
<>
<PostList posts={posts} /> {/* server */}
<SearchBox /> {/* client island */}
</>
);
}
A small interactive island in a sea of static, server-rendered content — that's the shape you're aiming for.
Pass data down, not functions
Server components can render client components and pass them serializable props — strings, numbers, plain objects. They can't pass functions. So shape your data on the server and hand the client component exactly what it needs to render:
<WorkFilters items={projects} /> // data in, interactivity inside
A simple decision rule
Ask one question of each component: does this need the browser?
- No — leave it as a server component. Most of your UI lands here.
- Yes — it uses state, effects, event handlers, or browser APIs? Mark it
"use client", and keep it small.
Think of client components as islands of interactivity, not the continent. The continent should be server-rendered HTML.
This model is why an App Router site can feel instant: the browser gets meaningful HTML immediately and only hydrates the few pieces that actually need to be interactive. Less JavaScript, faster pages, better Core Web Vitals — all from respecting one boundary.
Keep reading


