Inspired by the insights in Lydia Hallie & Addy Osmani’s Learning Patterns.
Why look beyond classic SSR?
Server‑side rendering (SSR) was a game‑changer for the initial performance of React apps. But as applications grew, teams hit a few pain points:
- Bundle duplication – The same components get shipped to both server and client.
- Hydration costs – After HTML is streamed, the browser must download JavaScript, parse it, and re‑attach event listeners.
-
Tight data -- UI coupling – Fetching data inside
getServerSideProps(or equivalent) forces full‑page reloads when only a section needed updating. - Limited in‑flight streaming – You can send HTML early, but JavaScript for large chunks often arrives all at once.
React Server Components (RSC) aim to address these issues while preserving React’s developer experience.
What is a Server Component?
A server component is rendered only on the server. It never appears in the client bundle, so there is zero JavaScript cost for that component in the browser.
// app/page.tsx (Next.js 14+)
import ProductList from "./ProductList"; // ✅ server component
export default async function Page() {{
const products = await fetchProducts(); // runs on the server
return (
<main className="p-6">
<h1 className="text-3xl font-semibold mb-4">Our catalog</h1>
{/* ProductList is rendered on the server;
the HTML is streamed to the client. */}
<ProductList products={{products}} />
</main>
);
}}
Key characteristics
- Can
awaitdatabase or API calls directly. - Output is HTML only; no client‑side JS bundle.
- Can render client components as children (marked with
"use client").
Automatic Code Splitting (RSC vs. React.lazy())
Traditional React relies on dynamic import patterns:
// Before
import React, {{ lazy, Suspense }} from "react";
const HeavyChart = lazy(() => import("./HeavyChart"));
export function Dashboard() {{
return (
<Suspense fallback={{<Spinner/>}}>
<HeavyChart />
</Suspense>
);
}}
With Server Components, React performs tree‑shaking on the server:
// After – HeavyChart is a Server Component
// It is excluded from the client bundle automatically.
import HeavyChart from "./HeavyChart"; // no 'lazy' needed
export function Dashboard() {{
return (
<>
<Summary />
<HeavyChart /> {/* streamed as HTML; zero JS sent */}
</>
);
}}
Because HeavyChart never reaches the browser, code splitting becomes implicit—React ships only the minimal JS required for interactive parts.
SSR vs. Server Components — at a glance
| Capability | Classic SSR | React Server Components |
|---|---|---|
| Eliminates client JS for non‑interactive UI | ❌ No (hydration needed) | ✅ Yes |
| Can access secure server resources during render | ✅ Yes | ✅ Yes |
| Partial streaming without extra bundling config | 🚧 Limited | ✅ Built‑in |
| Requires hydration cost in the browser | ✅ Always | ⚠️ Only for client components |
Works with existing useEffect, DOM APIs |
✅ Yes | ⚠️ Only inside client components |
| Ships duplicate logic (server + client) | ✅ Often | ❌ Never for pure server components |
Putting it together
Server Components complement — not replace — SSR:
- SSR is still useful for the shell of your page and for client components that need early HTML.
- RSC lets you push heavy, non‑interactive work entirely to the server, trimming bundles and hydration time.
In practice you’ll mix them:
// 'layout.tsx' is a server component by default
import "@/styles/globals.css";
import {{ Suspense }} from "react";
export default function RootLayout({{ children }}) {{
return (
<html>
<body>
<NavBar /> {/* client component */}
<Suspense fallback={{<Skeleton/>}}>
{{children}} {/* could include server + client parts */}
</Suspense>
</body>
</html>
);
}}
Conclusion
React Server Components let you scale UX and codebases without punishing runtime performance:
- Smaller client bundles – ship less JavaScript.
- Faster TTI – fewer hydration bytes, more streaming.
-
Simpler data fetching –
awaitdirectly in components. - Automatic code splitting – implicit through server‑only execution.
As teams iterate, learning when to choose a client vs. server boundary becomes the new architecture art. Learning Patterns reminds us that patterns evolve; RSC is the natural next turn in React’s performance playbook.
Happy hacking—see you in the diff!
Top comments (0)