The Problem Server Components Solve
Modern React applications often ship large JavaScript bundles to the browser. Every component, its dependencies, and the data-fetching logic all get downloaded, parsed, and executed on the client. For data-heavy pages, this means users wait for JavaScript to load before they see any content, even when much of that content is static.
React Server Components address this by letting you run components entirely on the server. These components render to HTML on the server and stream the result to the client. They never appear in the client-side JavaScript bundle, which means faster page loads and less work for the browser.
Server Components vs. Client Components
In the React Server Components model, every component is a Server Component by default. To make a component interactive on the client, you explicitly mark it with the "use client" directive.
// This is a Server Component by default
// It runs on the server and never ships to the browser
async function PostList() {
const posts = await db.posts.findMany();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
"use client";
// This is a Client Component
// It ships to the browser and can use hooks and event handlers
import { useState } from "react";
function LikeButton({ postId }) {
const [liked, setLiked] = useState(false);
return (
<button onClick={() => setLiked(!liked)}>
{liked ? "Liked" : "Like"}
</button>
);
}
The key distinction is that Server Components can access server-side resources directly, such as databases, file systems, and environment variables, without exposing them to the client.
Benefits of Server Components
Server Components offer several practical advantages:
- Smaller bundles: Libraries used only on the server are excluded from the client bundle entirely
- Direct data access: You can query databases and read files without building API endpoints
- Streaming: Content renders progressively as data becomes available, rather than waiting for everything to load
- Automatic code splitting: The boundary between server and client components creates natural split points
Composition Patterns
Server Components and Client Components can be composed together. A Server Component can render a Client Component, and it can pass serializable props to it. However, a Client Component cannot import a Server Component directly.
A common pattern is to fetch data in a Server Component and pass it as props to a Client Component that handles the interactive parts. This keeps data-fetching on the server while enabling interactivity where you need it.
Getting Started
The easiest way to use Server Components today is through a framework like Next.js, which provides the bundler integration and server infrastructure needed to make them work. As the ecosystem matures, expect more frameworks to adopt this model as the default way to build React applications.