TL;DR
React Server Components (RSC) are components rendered on the server that don't send JavaScript to the browser. They reduce bundle size, improve performance and SEO. Here's how they work and when to use them in 2026.
Who this is for
- React/Next.js developers wanting to improve performance
- Teams building applications with lots of data
- Companies seeking better SEO and faster load times
Keyword (SEO)
react server components, rsc, nextjs server components, react performance, server-side rendering
What are React Server Components?
React Server Components are:
- Components rendered only on the server
- Zero JavaScript sent to the browser
- Direct access to databases and APIs
- Smaller bundles and faster loading
Key differences:
| Server Components | Client Components |
|---|---|
| Render on server | Render in browser |
| No JavaScript | JavaScript in bundle |
| Access to DB/API | Only fetch |
| No interactivity | Full interactivity |
How do Server Components work?
1. Server-side rendering
Server Component:
// app/products/page.tsx
async function ProductsPage() {
// Direct database access
const products = await db.products.findMany();
return (
<div>
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
What happens:
- Server renders the component
- Sends HTML to browser
- Zero JavaScript for this component
2. Client Components for interactivity
When you need interactivity:
'use client'; // Directive for Client Component
import { useState } from 'react';
export function AddToCartButton({ productId }: { productId: number }) {
const [loading, setLoading] = useState(false);
const handleClick = async () => {
setLoading(true);
await addToCart(productId);
setLoading(false);
};
return (
<button onClick={handleClick} disabled={loading}>
Add to cart
</button>
);
}
Benefits of Server Components
1. Smaller JavaScript bundle
Before RSC:
- All components in bundle
- Large size (500KB+)
- Slow loading
With RSC:
- Only Client Components in bundle
- Smaller size (50-100KB)
- Faster loading
2. Direct data access
Without RSC:
'use client';
useEffect(() => {
fetch('/api/products')
.then(res => res.json())
.then(setProducts);
}, []);
With RSC:
async function ProductsPage() {
const products = await db.products.findMany();
// No fetch, no useEffect
return <ProductList products={products} />;
}
3. Better SEO
- Full HTML immediately in response
- No JavaScript required for rendering
- Faster indexing by Google
4. Security
Secret API keys:
// Server Component - safe
async function PaymentPage() {
const apiKey = process.env.STRIPE_SECRET_KEY; // ✅ Safe
// ...
}
// Client Component - UNSAFE
'use client';
const apiKey = process.env.STRIPE_SECRET_KEY; // ❌ Visible in bundle!
When to use Server Components?
✅ Use Server Components for:
Displaying data
- Product lists
- Blog posts
- Statistics
- Data tables
Static sections
- Header/Footer
- Navigation
- Sidebar
- SEO metadata
Database access
- Prisma queries
- SQL queries
- API calls with secrets
❌ Use Client Components for:
Interactivity
- Forms
- Buttons
- Dropdowns
- Modals
React Hooks
- useState
- useEffect
- useContext
- useReducer
Event handlers
- onClick
- onChange
- onSubmit
Next.js 13+ App Router
Structure:
app/
layout.tsx # Server Component (default)
page.tsx # Server Component
products/
page.tsx # Server Component
[id]/
page.tsx # Server Component
components/
Button.tsx # Client Component ('use client')
Example:
// app/products/page.tsx (Server Component)
import { db } from '@/lib/db';
import { ProductCard } from '@/components/ProductCard';
import { AddToCartButton } from '@/components/AddToCartButton';
export default async function ProductsPage() {
const products = await db.products.findMany();
return (
<div>
<h1>Products</h1>
{products.map(product => (
<div key={product.id}>
<ProductCard product={product} />
<AddToCartButton productId={product.id} />
</div>
))}
</div>
);
}
Best Practices
1. Default to Server Components
Rule: Everything is a Server Component unless you need interactivity.
// ✅ Server Component (default)
export function ProductList({ products }: { products: Product[] }) {
return (
<div>
{products.map(p => <ProductCard key={p.id} product={p} />)}
</div>
);
}
2. Minimize Client Components
Instead of:
'use client';
export function ProductPage() {
const [products, setProducts] = useState([]);
// ...
}
Better:
// Server Component
export default async function ProductPage() {
const products = await getProducts();
return <ProductList products={products} />;
}
3. Compose Server + Client
Pattern:
// Server Component
export default async function Page() {
const data = await fetchData();
return <InteractiveComponent data={data} />;
}
// Client Component
'use client';
export function InteractiveComponent({ data }: { data: Data }) {
const [state, setState] = useState();
// Interactivity with server data
}
4. Streaming and Suspense
Loading states:
import { Suspense } from 'react';
export default function Page() {
return (
<div>
<Suspense fallback={<Skeleton />}>
<ProductsList />
</Suspense>
</div>
);
}
FAQ
Do Server Components replace SSR?
No, they complement each other. SSR renders HTML on server but still sends JavaScript. RSC don't send JavaScript for server components.
Can I use hooks in Server Components?
No. Server Components cannot use React hooks (useState, useEffect, etc.). Only Client Components.
How to pass data from Server to Client Component?
Through props:
// Server Component
const data = await fetchData();
return <ClientComponent data={data} />;
Are Server Components faster?
Yes, because:
- Smaller JavaScript bundle
- No hydration for Server Components
- Faster first render