2 min read
Understanding React Server Components Without the Hype
RSC is not about killing client-side React — it's about choosing where each component pays its cost. A mental model that finally made it click for me.
When React Server Components landed in the App Router, most explanations jumped straight into rendering diagrams. What helped me was a simpler question: where does this component pay its cost — on the server at request time, or in the user's browser bundle?
The cost model
A server component never ships its code to the browser. Its dependencies — a markdown parser, a date library, a syntax highlighter — stay on the server. A client component ships everything it imports. That single fact explains most of the architecture advice you read.
My rule of thumb: start every component as a server component, and add "use client" only when the component needs state, effects, or browser APIs.
// Server component: data fetching stays on the server
export default async function PostList() {
const posts = await getAllPosts(); // no useEffect, no loading state
return posts.map((post) => <PostCard key={post._id} post={post} />);
}Where people get stuck
The boundary is contagious in one direction only. A client component cannot import a server component, but it can receive one as children. Composition, not imports, is how you interleave the two worlds.
Ship interactivity, not infrastructure. The browser should receive the pieces that respond to the user — nothing else.
Once that clicked, my bundle sizes dropped without a single optimisation pass — the framework was simply no longer shipping code that never needed to leave the server.