Understanding the Server/Client Boundary
React Server Components (RSC) allow components to run on the server, reducing bundle size and improving performance. But understanding when to use server vs. client components is critical.
Architecture Patterns
1. Data Fetching at the Component Level
Server components can directly access databases, file systems, and other server resources without API endpoints.
async function ProductList() {
const products = await db.product.findMany({ where: { published: true } });
return (
<div className="grid grid-cols-3 gap-4">
{products.map(p => <ProductCard key={p.id} product={p} />)}
</div>
);
}2. Server Actions for Mutations
Server Actions let you write async functions that run on the server and can be called from client components.
"use server";
export async function createProduct(formData) {
const product = await db.product.create({ data: { name: formData.get("name") } });
revalidatePath("/products");
return { success: true, product };
}Common Pitfalls
- You can't pass functions as props from server to client components
- You can't use useState or useEffect in server components
- Push "use client" as far down the component tree as possible
- Server components can't handle user interactions: use client components for that
Performance Impact
In our production app, moving to RSC reduced the JavaScript bundle by 35% and improved Time to Interactive by 40%. The key insight: server components aren't just about performance. They're about architectural clarity.
Conclusion
RSC is a paradigm shift, not just a feature. Think about the server/client boundary early in your architecture decisions.