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 being integrated into a single React tree with client components.
More simply:
RSC is a way to render part of a React application on the server, while keeping the rest of it interactive on the client, without duplicating logic or hydrating the entire tree as SSR would.
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 is sent to the client | Ready-made HTML | A stream of serialized components |
| What the client does | "Brings the HTML to life" (hydration) | Merges server and client components |
| When it runs | On every request | Can be at build time, at fetch time, or partially |
Where you can write fetch | Usually in getServerSideProps | Right inside the component! |
In other words, SSR = "render HTML on the server", while RSC = "render React components on the server without HTML".
3. How the RSC mechanism works
Step 1. Splitting components into types
RSC introduces two types of components:
| Type | Where it runs | Can it use Hooks / the DOM |
|---|---|---|
| Server Component | Only on the server | Cannot use useState, useEffect, window, document |
| Client Component | In the browser | Can use everything (hooks, the DOM, events, and so on) |
Marking it in code:
// This is a server component (by 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 ? "heart" : "outline heart"}</button>;
}Step 2. A server render returns not HTML but a React Payload
React Server Components do not send HTML. The server generates a stream of serialized React components, called React Flight Data.
An example (simplified):
[
["$","div",null,{"children":["Hello from server"]}],
["$","button","client:likeButton",{"children":["like"]}]
]The client receives this "JSON stream" and assembles the React tree using the RSC runtime.
In other words, the client does not receive HTML, but "instructions" for React on which components to render and which of them are client components.
Step 3. Merging (a hybrid tree)
On the client, React merges two worlds:
- Server components, already rendered ahead of time (their JS code is not even present on the client),
- Client components, which load, hydrate, and become interactive.
<App>
|-- <Header /> -> Server Component
|-- <PostList /> -> Server Component
| |-- <Post /> -> Server Component
| `-- <LikeButton /> -> Client Component
`-- <Footer /> -> Server ComponentThis way the client gets a minimal amount of JS - only for LikeButton.
Everything else is already rendered on the server and needs no hydration.
4. Benefits of RSC
| Benefit | Why it is great |
|---|---|
| Less JS on the client | The client does not need the server components' code at all |
| No double render (as with SSR) | RSC does not need HTML hydration - no duplication |
| Hybridity | Server and client components can be mixed in a single tree |
| Security | Server components never reach the client - keys or API tokens cannot accidentally leak |
| Faster rendering of large lists / data | Logic and requests run on the server, not in the browser |
| Compatible with Streaming SSR | Server and client parts can be streamed asynchronously |
5. An example of RSC in Next.js 13+ (App Router)
// app/page.tsx - Server Component (by 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 whole list of posts renders on the server, while the "like" button is interactive, but loads as 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" / an API | Right inside the components |
| Can it be mixed with client components | Limited | Yes, hybrid |
| Performance | Better than CSR, but requires a double render | Even better - 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 JS size and speeds up page loads,
- and lets you mix server and client code in a single tree.
If SSR = "the server generates HTML", then RSC = "the server generates a React tree". And that brings React closer to universal rendering - a smart, hybrid model where each component runs wherever it makes the most sense.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.