Server Components vs Client Components ("use client" boundary)0%
Data Fetching in Server Components & Async Server Logic

Server Components vs Client Components ("use client" boundary)

Beginner12 min read•Updated: Jul 11, 2026
Study MaterialsCheatsheet

Server Components vs Client Components ("use client" boundary)

Understanding when to use React Server Components (RSC) and when to introduce the "use client" boundary is the single most important conceptual skill in modern Next.js engineering.


1. Comparing Server vs Client Components

FeatureServer Components (Default)Client Components ("use client")
Execution EnvironmentRuns only on the serverPre-rendered on server, hydrated in browser
Browser Bundle Impact0 KB (Dependencies stay on server)Added to browser JavaScript bundle
Direct Backend AccessFull access to databases, filesystems, env secretsNo direct access to databases/secrets
React Hooks❌ No useState, useEffect, useReducer✅ Full access to state, lifecycle, and custom hooks
Browser APIs & Events❌ No onClick, onChange, window, localStorage✅ Full access to DOM events and browser APIs

2. The "use client" Boundary

Adding "use client" at the very top of a file declares a boundary between server-only code and code that needs client interactivity. It does NOT mean the component runs only on the client! It will still be pre-rendered to HTML on the server during initial load, then hydrated in the browser with event listeners.

TSX
// components/CounterButton.tsx
'use client'; // This directive defines the client boundary!
 
import { useState } from 'react';
 
export default function CounterButton({ initialCount = 0 }: { initialCount?: number }) {
const [count, setCount] = useState(initialCount);
 
return (
<button
onClick={() => setCount(count + 1)}
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
>
Enrolled Students: {count}
</button>
);
}

3. Composing Server and Client Components (The Golden Rule)

"Push client components down to the leaves of your component tree."

Instead of marking your entire page with 'use client', keep your layout and pages as Server Components (fetching data and securing secrets), and only import small client components where interactivity is strictly required:

TSX
// app/courses/[slug]/page.tsx (Server Component - fetches data securely)
import { getCourseFromDb } from '@/lib/db';
import CounterButton from '@/components/CounterButton'; // Client Component imported as leaf!
 
export default async function CoursePage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const course = await getCourseFromDb(slug); // Direct database query!
 
return (
<div className="p-8">
<h1 className="text-3xl font-bold">{course.title}</h1>
<p>{course.description}</p>
 
{/* Interactive client component receives server data as props */}
<CounterButton initialCount={course.enrolledCount} />
</div>
);
}

Interactive Quiz

Multiple Choice Questions

Question 1
What does adding the 'use client' directive at the top of a file do?
Question 2
Why should developers "push client components down to the leaves of the component tree"?
Question 3
Which of the following is strictly prohibited inside a React Server Component?
Question 4
Can a Server Component be passed as a children prop into a Client Component?
Question 5
Why are secret API keys and database credentials safe inside a Server Component?

Next Lesson

Data Fetching in Server Components & Async Server Logic

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext