React Server Components Explained
Understanding the new React Server Components

Jane Doe
@janedoeReact Server Components Explained
React Server Components (RSC) are a new feature that allows components to be rendered on the server, significantly improving performance and reducing bundle sizes.
What are Server Components?
Server Components are React components that render on the server and send their output to the client as HTML. Unlike traditional SSR, they:
- Never re-render on the client
- Can directly access backend resources
- Don't increase bundle size
- Can use async/await at the component level
Key Benefits
1. Zero Bundle Size
Server Components don't add to your JavaScript bundle:
// This component runs only on the server
async function DatabaseList() {
const items = await db.query('SELECT * FROM items');
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
2. Direct Backend Access
Access databases, file systems, or internal APIs directly:
async function UserProfile({ userId }) {
// Direct database access - no API needed
const user = await db.users.findById(userId);
const posts = await db.posts.findByUser(userId);
return (
<div>
<h1>{user.name}</h1>
<PostList posts={posts} />
</div>
);
}
3. Automatic Code Splitting
Server Components enable more granular code splitting without manual lazy loading.
Server vs Client Components
Server Components (Default)
// app/page.tsx - Server Component by default
async function Page() {
const data = await fetch('https://api.example.com/data');
return <div>{/* Render data */}</div>;
}
Client Components
'use client'; // Opt into client-side rendering
import { useState } from 'react';
function InteractiveButton() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
When to Use Each
Use Server Components for:
- Static content
- Data fetching
- Large dependencies
- Server-only secrets
Use Client Components for:
- Interactivity (onClick, onChange)
- Browser APIs
- State management
- Real-time updates
Patterns and Best Practices
Composition Pattern
// Server Component
async function ProductPage({ id }) {
const product = await getProduct(id);
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
{/* Client Component for interactivity */}
<AddToCartButton productId={id} />
</div>
);
}
Data Fetching Pattern
// Parallel data fetching
async function Dashboard() {
// These requests happen in parallel
const [user, posts, comments] = await Promise.all([
getUser(),
getPosts(),
getComments()
]);
return (
<div>
<UserInfo user={user} />
<PostList posts={posts} />
<CommentList comments={comments} />
</div>
);
}
Performance Implications
Before Server Components
Initial Load: HTML + Large JS Bundle
Hydration: Re-render everything
Data Fetching: After hydration
With Server Components
Initial Load: HTML + Minimal JS
Hydration: Only interactive parts
Data Fetching: During SSR
Common Pitfalls
1. Trying to use hooks in Server Components
// ❌ This won't work
async function ServerComponent() {
const [state, setState] = useState(); // Error!
}
2. Importing Server Components in Client Components
'use client';
// ❌ Can't import Server Component directly
import ServerComponent from './ServerComponent';
3. Passing functions as props
// ❌ Functions can't be serialized
<ServerComponent onClick={() => {}} />
Migration Strategy
- Start with leaves (components without children)
- Identify purely presentational components
- Move data fetching to Server Components
- Keep interactive parts as Client Components
Conclusion
React Server Components represent a fundamental shift in how we think about React applications. By moving more work to the server, we can build faster, more efficient applications while maintaining the developer experience we love.
Further Reading
Share this post: