React Server Components: The Mental Model That Finally Clicked
When React Server Components landed in Next.js App Router, I spent weeks writing them without fully understanding the model. Then one diagram changed everything. Let me share that mental model.
Two trees, one output
Your app renders two component trees: one on the server (Server Components) and one on the client (Client Components). The server tree can include client subtrees — but not vice versa.
The serialization boundary
Props that cross the server → client boundary must be serializable. No functions, no class instances, no React elements as props (unless using children/slots).
Data fetching belongs at the top
Fetch data as high as possible in the server tree, then pass it down as props. Avoid waterfalls by fetching in parallel with Promise.all.
// app/dashboard/page.tsx (Server Component)
export default async function DashboardPage() {
const [user, orders] = await Promise.all([
getUser(),
getOrders(),
])
return <Dashboard user={user} orders={orders} />
}
Client Components are islands
Think of 'use client' as a boundary marker, not a file-level directive. Everything imported into a Client Component also becomes client-side. Keep the island small.
Once this model clicked, I stopped fighting the framework. RSC is a genuinely better architecture for data-heavy apps — less JavaScript, faster page loads, simpler data flow.
More posts


