What are React Server Components (RSC)?
1. What React Server Components (RSC) are
React Server Components (RSC) are components that run on the server, not in the browser, while still integrating into a single React tree with client components.
Put simply:
RSC is a way to render part of a React application on the server, while keeping the rest interactive on the client, without duplicating logic or SSR-hydrating the entire tree.
2. How RSC differs from SSR
| Criterion | SSR (Server-Side Rendering) | RSC (React Server Components) |
|---|---|---|
| Where it runs | The server generates HTML | The server generates a React structure (tree) |
| What's sent to the client | Ready-made HTML | A stream of serialized components |
| What the client does | "Brings the HTML to life" (hydration) | Combines server and client components |
| When it runs | On every request | Can happen at build time, on fetch, or partially |
| Where you can write fetch | Usually in getServerSideProps | Right inside the component! |
In other words, SSR = "rendering HTML on the server", and RSC = "rendering React components on the server without HTML".
3. How the RSC mechanism works
Step 1. Splitting into component types
RSC introduces two types of components:
| Type | Where it runs | Can you use Hooks / DOM |
|---|---|---|
| Server Component | Only on the server | No useState, useEffect, window, document |
| Client Component | In the browser | Everything is allowed (hooks, DOM, events, etc.) |
Notation in code:
// This is a server component (the default)
export default async function Page() {
const data = await fetch('https://api.example.com/posts').then(r => r.json());
return <PostList posts={data} />;
}
// This is a client component
"use client";
import { useState } from "react";
export function LikeButton() {
const [liked, setLiked] = useState(false);
return <button onClick={() => setLiked(!liked)}>{liked ? "Liked" : "Not liked"}</button>;
}Step 2. Server rendering returns not HTML, but a React Payload
React Server Components don't send HTML. The server generates a stream of serialized React components called React Flight Data.
Example (simplified):
[
["$","div",null,{"children":["Hello from server"]}],
["$","button","client:likeButton",{"children":["Liked"]}]
]The client receives this "JSON stream" and assembles the React tree using the RSC runtime.
In other words, the client receives not HTML, but "instructions" for React about which components to render and which ones are client components.
Step 3. Combination (a hybrid tree)
On the client, React combines two worlds:
- Server components: already rendered ahead of time (their JS code isn't even present on the client),
- Client components: loaded, hydrated, and made interactive.
<App>
├── <Header /> → Server Component
├── <PostList /> → Server Component
│ ├── <Post /> → Server Component
│ └── <LikeButton /> → Client Component
└── <Footer /> → Server ComponentThis way, the client receives minimal JS: only for LikeButton. Everything else is already rendered on the server and doesn't require hydration.
4. Advantages of RSC
| Advantage | Why it's great |
|---|---|
| Less JS on the client | The client doesn't need the server components' code at all |
| No double render (unlike SSR) | RSC doesn't require HTML hydration, so there's no duplication |
| Hybrid nature | You can mix server and client components in one tree |
| Security | Server components never reach the client, so keys or API tokens can't accidentally leak |
| Faster rendering of large lists / data | Logic and requests run on the server, not the browser |
| Compatible with Streaming SSR | Server and client parts can be streamed asynchronously |
5. RSC example in Next.js 13+ (App Router)
// app/page.tsx - Server Component (the default)
import Posts from './Posts';
export default async function Page() {
const posts = await fetch('https://jsonplaceholder.typicode.com/posts').then(r => r.json());
return (
<main>
<h1>Server-rendered posts</h1>
<Posts posts={posts} />
</main>
);
}// app/Posts.tsx - Server Component
import LikeButton from './LikeButton';
export default function Posts({ posts }) {
return (
<ul>
{posts.map(p => (
<li key={p.id}>
{p.title} <LikeButton />
</li>
))}
</ul>
);
}// app/LikeButton.tsx - Client Component
"use client";
import { useState } from "react";
export default function LikeButton() {
const [liked, setLiked] = useState(false);
return (
<button onClick={() => setLiked(!liked)}>
{liked ? "Liked" : "Not liked"}
</button>
);
}The entire list of posts is rendered on the server, while the "like" button is interactive, but loads in a separate JS chunk.
6. RSC ≠ SSR
| Difference | SSR | RSC |
|---|---|---|
| Output format | HTML | React Payload (instructions) |
| Hydration | Required | Not needed |
| Where the data logic lives | In "getServerSideProps" / API | Right inside the components |
| Can it mix with client components | Limited | Yes, hybrid |
| Performance | Higher than CSR, but requires a double render | Even higher: less JS and less HTML |
Summary
React Server Components (RSC) are a new foundation for React that:
- moves part of the logic and rendering to the server,
- leaves interactivity to the client,
- removes the need for "hydration" for static parts,
- reduces the size of the JS and speeds up page loading,
- and lets you mix server and client code in one tree.
If SSR = "the server generates HTML", then RSC = "the server generates a React tree". And this brings React closer to universal rendering: a smart, hybrid model where each component runs wherever it's more efficient.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.