React Server Components
Overview
For its first decade, React was purely a client-side library. When a user visited a URL, the server sent a blank HTML page and a massive JavaScript file. The browser had to download the JS, run React, and calculate the UI, resulting in a blank white screen during the loading phase.
React 18 and Next.js 13 fundamentally shifted the architecture of the entire internet by introducing React Server Components (RSC).
Server Components are React components that run exclusively on the backend server. They never ship to the browser. This means you can write heavy data-fetching logic, query a database directly, or import massive node modules (like a markdown parser) directly inside your React component, and the user's browser never has to download a single kilobyte of that code. The server runs the component, generates pure, instantaneous HTML, and sends that to the browser.
Syntax
import db from '@/lib/db';
// 1. Notice the 'async' keyword! This is physically impossible in traditional React.
// 2. This component runs securely on your Node.js server. It NEVER runs in the browser.
export default async function UserDashboard() {
// 3. We can query the database directly inside the component!
// No more useEffect, no more loading spinners, no more API routes.
const users = await db.user.findMany({ where: { active: true } });
return (
<main>
<h1>Active Users</h1>
<ul>
{users.map(user => (
<li key={user.id}>{user.name} - {user.email}</li>
))}
</ul>
</main>
);
}Common Pitfalls
- Trying to use State or Effects in an RSC: Because Server Components run on the server (which is stateless and immediately terminates after generating the HTML), you absolutely CANNOT use
useState,useEffect,onClick, oruseRef. If a component needs interactivity (like a button click or a toggle), it must be a Client Component.
Interview Questions
1. Zero Bundle Size: The code for RSCs is never sent to the browser, making the app blazingly fast. 2. Direct Backend Access: RSCs can securely read from databases or file systems without needing separate API routes. 3. SEO: The server sends fully populated HTML to the browser instantly, which web crawlers (Google) can perfectly read.
onClick handler?Because Server Components are executed on the backend to generate static HTML, and their JavaScript is never shipped to the client's browser. An onClick handler requires JavaScript running actively in the user's browser to listen for the mouse event. If you need interactivity, you must convert it to a Client Component.
Real-World Example
Mixing Server and Client Components: This is the 'Holy Grail' pattern of modern React. You use Server Components at the very top of your file tree to handle all data fetching and layout generation, and you sprinkle small, isolated Client Components into the tree only where user interactivity (like a button) is explicitly required.
import db from '@/db';
// We import an interactive Client component into our Server component
import { LikeButton } from './LikeButton';
// SERVER COMPONENT (Fetches data securely, sends 0kb of JS to the browser)
export default async function BlogPost({ params }) {
// Direct DB access!
const post = await db.post.findById(params.id);
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.htmlContent }} />
{/* We pass the data down to the Client Component for interactivity */}
<LikeButton initialLikes={post.likes} postId={post.id} />
</article>
);
}Check Your Knowledge
Test your understanding of React Server Components with these quick questions.