Published Mar 19, 2026
Understanding React Server Components in Next.js apps
React Server Components represent a fundamental shift in how we build React applications. They run exclusively on the server, which means they can directly access databases, read files, and fetch data — all without sending any JavaScript to the browser.
Server vs Client Components
In Next.js App Router, every component is a Server Component by default. To make a component run on the client, you add the 'use client' directive at the top of the file.
Server Components can:
- Fetch data directly (no API routes needed)
- Access backend resources
- Keep sensitive logic server-side
- Reduce client bundle size
Client Components are needed for:
- Interactivity (
onClick,onChange, etc.) - State management (
useState,useReducer) - Browser APIs (
localStorage,window) - Effects (
useEffect,useLayoutEffect)
The mental model
Think of it this way: Server Components are your data layer, Client Components are your interaction layer. The boundary between them is the 'use client' directive.
// app/posts/page.tsx — Server Component
import { getPosts } from '@/lib/posts';
import { PostList } from './post-list';
export default async function PostsPage() {
const posts = await getPosts();
return <PostList posts={posts} />;
}
// app/posts/post-list.tsx — Client Component
'use client';
import { useState } from 'react';
export function PostList({ posts }) {
const [search, setSearch] = useState('');
const filtered = posts.filter(p =>
p.title.toLowerCase().includes(search.toLowerCase())
);
return (
<div>
<input value={search} onChange={e => setSearch(e.target.value)} />
{filtered.map(post => <article key={post.slug}>{post.title}</article>)}
</div>
);
}
Common mistakes
Moving the 'use client' boundary too high. If you put 'use client' on a layout or page, everything below it becomes a Client Component. Push the boundary as low as possible — wrap only the interactive parts.
Trying to pass functions as props from Server to Client Components. Functions are not serializable, so you cannot pass callbacks from a Server Component to a Client Component. Instead, use Server Actions.
Fetching data in Client Components when you do not need to. If the data does not change based on user interaction, fetch it in a Server Component and pass it down as props.
Server Components are not a replacement for Client Components — they are complementary. The goal is to use each where it makes the most sense.