What is React Server Components?
React Server Components are a React architecture that renders components on the server, sending only their output to the client.
What are React Server Components?
React Server Components (RSC) are a React rendering architecture where specific components execute exclusively on the server, sending a serialized UI description—not their source code—to the client. First proposed by the React team in December 2020 and shipped as stable in Next.js 13.4 (May 2023), RSC fundamentally changes the component model by splitting the tree into server and client subtrees.
Server Components can directly access databases, file systems, and private APIs without exposing secrets or shipping dependency code to the browser. In practice, this means a component that imports a 200 KB Markdown parser adds zero bytes to the client bundle.
RSC is the default in Next.js App Router: every component is a Server Component unless you add the 'use client' directive. We've shipped this on 50+ projects and consistently see 30–50% reductions in client-side JavaScript.
How it works
When a request hits the server, React renders the Server Component tree into a special wire format called the RSC payload—a streaming, JSON-like protocol that describes the component output (elements, props, references to Client Components) without including the component functions themselves.
Here's the mental model:
- Server phase: React calls your Server Components, resolves any
asyncdata fetching (yes, Server Components can beasyncfunctions), and produces the RSC payload. - Streaming: The payload streams to the client over HTTP, chunk by chunk, which pairs naturally with
<Suspense>boundaries. - Client reconciliation: React on the client deserializes the payload, stitches in Client Component subtrees (marked with
'use client'), and hydrates only those interactive parts.
// app/dashboard/page.tsx — Server Component by default
import { db } from '@/lib/db';
import { Chart } from '@/components/Chart'; // 'use client' inside
export default async function DashboardPage() {
const metrics = await db.query('SELECT * FROM metrics WHERE org_id = $1', [orgId]);
return (
<section>
<h1>Dashboard</h1>
{/* Chart is a Client Component; it receives serializable props */}
<Chart data={metrics} />
</section>
);
}
Key constraints: Server Components can't use useState, useEffect, or any browser API. Props passed from Server to Client Components must be serializable (no functions, no classes). Violating either produces a build-time or runtime error in Next.js.
Server Actions (the 'use server' directive) complement RSC by letting Client Components call server-side mutations without writing API routes—these shipped stable in Next.js 14 (October 2023).
When to use it
RSC shines when you need data-heavy pages with minimal interactivity, or when you're trying to shrink bundle size.
Use RSC when:
- Fetching data at the component level (co-located queries instead of centralized loaders)
- Rendering Markdown, syntax highlighting, or content that depends on large libraries the client doesn't need
- Building dashboards, documentation sites, or e-commerce product pages
- You want to keep API keys and database credentials off the client entirely
Skip RSC (or think twice) when:
- Your app is almost entirely interactive (real-time editors, games)—you'll end up marking everything
'use client'anyway - You're locked into a non-RSC framework like Remix (as of April 2026, Remix hasn't adopted RSC)
- Your team isn't on Next.js 13.4+ or a framework with RSC support
- You need to share component logic between server and client in ways that fight the serialization boundary
Our preferred stack is Next.js App Router with RSC defaults. For purely interactive SPAs, we still reach for Vite + React.
React Server Components vs alternatives
| Approach | JS shipped to client | Data fetching | Interactivity | Framework support |
|---|---|---|---|---|
| React Server Components | Only Client Components | In-component, server-side | Client Components only | Next.js, Waku |
| SSR (traditional) | Full component tree | getServerSideProps / loaders |
Full hydration | Next.js Pages, Remix |
| Static Site Generation | Full component tree | Build-time only | Full hydration | Next.js, Astro |
| Astro Islands | Only island components | Astro frontmatter / loaders | Opt-in islands | Astro |
The closest analog to RSC outside React is Astro's zero-JS-by-default model with islands. The difference: RSC preserves React's component model and state tree across navigations, while Astro islands are framework-agnostic but don't share a unified component tree. If you're already in the React ecosystem, RSC is the natural path. If you're framework-flexible and content-heavy, Astro is worth evaluating.
Real-world example
We rebuilt a client's marketing site (120+ pages, heavy on long-form content with embedded code samples) from Next.js Pages Router to App Router with RSC. The content pages used rehype and shiki for Markdown and syntax highlighting—together about 180 KB of dependencies.
With RSC, those libraries run only on the server. The result: client JS per page dropped from 310 KB to 140 KB (gzipped), Largest Contentful Paint improved from 2.8s to 1.6s on mobile 4G (measured in Chrome UX Report data), and Time to Interactive dropped by over a second. The only Client Components on those pages were a table-of-contents sidebar with scroll tracking and a feedback widget—about 12 KB total.