Learn the concept
Server & Client Components
Server Components render on the server with no JavaScript sent to the client, ideal for data fetching and static content. Client Components (marked with 'use client') render on both server and client, enabling interactivity like state and event handlers.
Server Components (Default in App Router):
await data directlyuseState, useEffect, event handlers, browser APIsClient Components:
'use client' directive at top of fileComposition Pattern:
Best Practice:
'use client' as far down the tree as possibleReact 19 Integration:
async functions (React 19 native support)use() hook for reading promises and context in Client Components// app/posts/page.tsx - Server Component
// No 'use client' = Server Component by default
import { db } from '@/lib/db'; // Can access DB directly!
export default async function PostsPage() {
// ✅ Can await data directly
const posts = await db.posts.findMany();
// ✅ Can access server-only resources
const apiKey = process.env.SECRET_API_KEY;
// ❌ Cannot use hooks
// const [count, setCount] = useState(0); // Error!
// ❌ Cannot use event handlers directly
// <button onClick={() => {}}>Click</button> // Error!
return (
<div>
<h1>Posts</h1>
{posts.map((post) => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.content}</p>
</article>
))}
</div>
);
}Using Server Components for blog posts and documentation pages that ship zero JavaScript to the client
Keeping the page shell as Server Components while wrapping only interactive widgets in Client Components
Querying databases and accessing secrets directly in Server Components without exposing credentials to the client
Build an app demonstrating the composition pattern: Server Component page with Client Component interactive sections using the children pattern
Build the same feature twice (all Client Components vs mixed) and compare bundle sizes using @next/bundle-analyzer