RSC – React Server Components

Rendering & Architecture

Understanding React Server Components (RSC)

React Server Components (RSC) represent the biggest architectural shift in the React ecosystem since hooks. Traditionally, React components (even with SSR) were always sent to the browser to be hydrated. Server Components, however, never leave the server.

They run exclusively on the server and render into a special JSON format (the "RSC Payload") that the browser uses to update the DOM. This means the code for a Server Component is never included in the JavaScript bundle sent to the client.

The RSC Execution Flow

  1. Request: The browser requests a page.
  2. Server Execution: React renders the Server Components. It can directly access the database or filesystem.
  3. Serialization: The result is serialized into a compact JSON format (not HTML).
  4. Streaming: This payload is streamed to the browser.
  5. Reconciliation: The browser receives the payload and merges it into the existing DOM tree without destroying the state of Client Components.

Why Use RSC?

RSC solves several long-standing issues in frontend development, primarily related to bundle size and data fetching.

1. Zero Bundle Size

Dependencies used inside a Server Component are not sent to the browser. If you use a heavy library like moment.js or a markdown parser to render static content, the user downloads 0KB of that library.

2. Direct Backend Access

Since Server Components run on the server, you don't need to build an API endpoint just to fetch data for your component. You can query your database directly inside your component.

3. Automatic Code Splitting

Client Components imported into Server Components are automatically code-split. You don't need React.lazy or dynamic imports manually; Next.js handles it for you.


Server vs. Client Components

The new mental model requires distinguishing between "Server" and "Client" environments.

Server Components (Default)

  • Where: Run only on the server.
  • Can: Fetch data, access database, keep secrets (API keys).
  • Cannot: Use hooks (useState, useEffect), add event listeners (onClick), or access browser APIs (window, localStorage).
  • Use for: Data fetching, layout, static content.

Client Components ("use client")

  • Where: Prerendered on server, hydrated on client.
  • Can: Use state, effects, event listeners, browser APIs.
  • Cannot: Access database directly or keep secrets.
  • Use for: Interactivity (buttons, forms, animations).

🛠️ Implementing RSC in Next.js

In the Next.js App Router, all components are Server Components by default.

1. A Basic Server Component

Notice how we can make the component async and fetch data directly. No useEffect, no loading state management.

app/blog/[slug]/page.tsx
// app/blog/[slug]/page.tsx
import db from "@/lib/db";
 
// This is a Server Component
export default async function BlogPost({
  params,
}: {
  params: { slug: string };
}) {
  // Direct database access!
  const post = await db.post.findUnique({
    where: { slug: params.slug },
  });
 
  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}

2. Interleaving Server and Client Components

You can compose Client Components inside Server Components. This is the "holes in the donut" pattern.

app/page.tsx
// app/page.tsx (Server Component)
import { LikeButton } from "./LikeButton"; // Client Component
 
export default async function Page() {
  const content = await fetchContent();
 
  return (
    <main>
      <h1>{content.title}</h1>
      <p>{content.body}</p>
 
      {/* We can pass server data to the client component as props */}
      <LikeButton initialLikes={content.likes} />
    </main>
  );
}
app/LikeButton.tsx
// app/LikeButton.tsx (Client Component)
"use client";
 
import { useState } from "react";
 
export function LikeButton({ initialLikes }: { initialLikes: number }) {
  const [likes, setLikes] = useState(initialLikes);
 
  return <button onClick={() => setLikes(likes + 1)}>❤️ {likes} Likes</button>;
}

Conclusion: A New Era for React ⚛️

React Server Components are not just a performance optimization; they are a fundamental shift in how we build React applications. By moving the "heavy lifting" to the server and keeping the client bundle light, RSC allows us to build faster, more complex applications with a simpler developer experience.

The future of React is hybrid: leveraging the server for data and logic, and the client for rich, interactive experiences.