DEV Community

Cover image for Server Components Without the Hype: A Mental Model That Sticks
Parsa Jiravand
Parsa Jiravand

Posted on

Server Components Without the Hype: A Mental Model That Sticks

React Server Components confused a lot of people, and most of the confusion comes from pattern-matching them onto things we already knew — "oh, it's just SSR," or "it's like getServerSideProps." It isn't, quite. Here's a mental model that actually sticks.

The one distinction that matters

Forget rendering for a second. The real split is where a component's code lives and runs:

  • A Server Component runs only on the server. Its code never ships to the browser. It can read your database, touch the filesystem, use secrets — and then it disappears, leaving behind only the UI it produced.
  • A Client Component is the React you already know: its code ships to the browser, and it can use state, effects, and event handlers.

That's the whole core idea. Server Components are components whose JavaScript the user never downloads. Everything else follows from that.

Why this is different from SSR

Classic SSR renders your entire app to HTML on the server, then ships all the JS to the browser to "hydrate" it — make it interactive. You paid for the HTML and the full bundle.

RSC lets you say: this part of the tree is just display — render it on the server and don't send its code at all. Only the genuinely interactive bits become Client Components and ship their JS. The static 80% of a typical page stops costing you bundle size.

// Server Component — runs on the server, ships zero JS to the client.
// It can await data directly. No useEffect, no loading spinner plumbing.
async function ArticlePage({ id }: { id: string }) {
  const article = await db.articles.find(id); // safe: never runs in the browser
  return (
    <article>
      <h1>{article.title}</h1>
      <Markdown>{article.body}</Markdown>
      <LikeButton articleId={id} /> {/* the ONE interactive island */}
    </article>
  );
}
Enter fullscreen mode Exit fullscreen mode
"use client"; // this directive marks the boundary — code below ships to the browser
function LikeButton({ articleId }: { articleId: string }) {
  const [liked, setLiked] = useState(false);
  return <button onClick={() => setLiked(!liked)}>{liked ? "" : ""}</button>;
}
Enter fullscreen mode Exit fullscreen mode

The page's data-fetching and markup rendering cost zero client JS. Only LikeButton — the part that needs to do something on click — gets shipped.

The rules that trip people up (and why they exist)

  • Server Components can't use useState/useEffect/event handlers. They don't exist on the client, so there's no "interactive" lifecycle to hook into. If you need interactivity, you've found a Client Component.
  • You can pass a Server Component into a Client Component as children, but you can't import one into a client module. Because the moment you import it into client code, its server-only code would have to ship — defeating the point.
  • "use client" marks a boundary, not a file-by-file choice. Everything imported below that boundary is in client-land too. Put the directive as deep in the tree as you can.

Once you internalize "Server Components are the code that never ships," every one of those rules stops feeling arbitrary and starts feeling obvious.

When to actually reach for it

  • Default to Server Components. Make a component a Client Component only when it needs state, effects, browser APIs, or event handlers.
  • Push the "use client" boundary down. A whole page marked client-side throws away the benefit; an interactive leaf node keeps it.
  • Don't fight it for purely static sites. If there's barely any interactivity, a simpler static-generation setup may be all you need — RSC earns its complexity on data-heavy, partially-interactive apps.

The takeaway

Server Components aren't "SSR with extra steps." They're a way to write parts of your UI whose code never leaves the server — so the browser downloads only the JavaScript that genuinely needs to run there. Hold onto that one sentence and the rest of the model assembles itself.

Top comments (0)