React Server Components: What You Need to Know
React Server Components: What You Need to Know
React Server Components (RSC) fundamentally change how React apps are built. Components render on the server by default, sending only HTML and minimal JavaScript to the client. Understanding the mental model is key to using them effectively.
The Mental Model
In the RSC world, there are two kinds of components:
Server Components (default) — render on the server, have zero JavaScript bundle cost, can directly access databases and file systems, but cannot use state, effects, or browser APIs. Client Components — marked with"use client", render on both server (SSR) and client, can use hooks, event handlers, and browser APIs, but add to the JavaScript bundle.
// Server Component (default) — no directive needed
async function PostList() {
const posts = await db.post.findMany(); // Direct DB access
return (
{posts.map((post) => (
-
{/* Client Component */}
))}
);
}
"use client";
// Client Component — interactive
function LikeButton({ postId }: { postId: string }) {
const [liked, setLiked] = useState(false);
return (
{liked ? "Liked" : "Like"}
);
}
The Composition Rule
Server Components can import and render Client Components. Client Components cannot import Server Components — but they can accept them as children or other props:
// This works — Server Component passes children
function ServerWrapper() {
return (
{/* Rendered on server, passed as children */}
);
}
When to Use Client vs Server
Keep on the Server
Move to the Client
Data Fetching Patterns
Server Components can be async, making data fetching straightforward:
async function UserProfile({ userId }: { userId: string }) {
const user = await db.user.findUnique({ where: { id: userId } });
if (!user) return notFound();
return (
{user.name}
{user.bio}
}>
);
}
Performance Benefits
"use client" boundary.Common Pitfalls
Conclusion
Think of Server Components as your default. Start every component on the server, and only add "use client" when you need interactivity. This approach gives you the best performance, smallest bundles, and simplest data fetching patterns.