React Server Components (RSC) have been available since Next.js 13 App Router. But most developers still treat them like client components with a "use server" badge. Let's fix that.
Server Components run only on the server. They:
useState, useEffect, browser APIs// app/posts/page.tsx — this runs on the server
// No 'use client' = Server Component by default
async function PostsPage() {
// Direct DB query. No API route needed.
const posts = await db.post.findMany();
return (
<div>
{posts.map(post => (
<PostCard key={post.id} post={post} />
))}
</div>
);
}| Old React Thinking | RSC Thinking |
|---|---|
| Everything is a component | Components have two environments |
| Data fetching = useEffect | Data fetching = async/await in component |
| API routes for everything | Direct DB access in Server Components |
| Bundle size = full app | Bundle size = only interactive parts |
// ❌ Sequential — each awaits the previous
const user = await getUser();
const posts = await getPosts(user.id);
const comments = await getComments(posts[0].id);
// ✅ Parallel — all fire at once
const [user, posts] = await Promise.all([
getUser(),
getPosts()
]);Use 'use client' when you need:
useState / useReduceruseEffect / lifecycleIn a traditional SPA, you'd ship 200KB of JS to render a page that reads from a DB. With RSC, that same page ships 0KB of component JS — the HTML comes pre-rendered.
This is not incremental improvement. It's architectural shift.