Mastering React Server Components vs Client Components in Next.js
Learn the core differences between React Server Components and Client Components in Next.js to build faster, more efficient web applications.
Previously in this course, we explored the Understanding the App Router Architecture to map our URLs to the filesystem. Now that you have a basic project structure, we need to address the most critical performance decision you’ll make in every file: choosing between Server and Client Components.
In the App Router, components are Server Components by default. This is a paradigm shift from traditional React development, where everything lived in the browser. Understanding this boundary is key to writing modern, high-performance Next.js code.
The Core Concept: Where Does the Code Run?
In a standard React app, your entire component tree is sent to the browser, which then downloads, parses, and executes the JavaScript. In Next.js, we split this work:
- Server Components: These run exclusively on the server. They have direct access to backend resources like databases or file systems. They never ship their code to the browser, resulting in smaller bundle sizes and faster initial page loads.
- Client Components: These are rendered on the server once (to generate HTML) and then "hydrated" in the browser to become interactive. They have access to browser-specific APIs (like
window,localStorage, oruseState).
Comparison at a Glance
| Feature | Server Components | Client Components |
|---|---|---|
| Execution | Server only | Server (initial) + Browser |
| Data Fetching | Direct (async/await) | Via API/Hooks |
| Interactivity | No (no hooks) | Yes (hooks, event listeners) |
| Bundle Size | Zero impact | Increases with size |
Using the 'use client' Directive
Because all components are Server Components by default, you must explicitly opt-in to Client Component behavior. You do this by adding the 'use client' directive at the very top of your file.
Important: This directive isn't just a flag; it tells the Next.js compiler that this component—and any components it imports—should be treated as Client Components.
Worked Example: Building an Interactive Counter
Let's apply this to our blog project. We want a "Like" button on our blog post page. Since this requires state (to track clicks), it must be a Client Component.
Create a new file: components/LikeButton.js
JAVASCRIPTCE9178">'use client'; // This directive is mandatory! import { useState } from CE9178">'react'; export default function LikeButton() { const [likes, setLikes] = useState(0); return ( <button onClick={() => setLikes(likes + 1)}> Likes: {likes} </button> ); }
Now, you can import this into a Server Component (like your page.js):
JAVASCRIPT// app/blog/[slug]/page.js import LikeButton from CE9178">'@/components/LikeButton'; export default function BlogPost() { return ( <article> <h1>My Blog Post</h1> <p>This is rendered on the server.</p> <LikeButton /> {/* Interactive part runs on the client */} </article> ); }
Performance Optimization Strategy
The golden rule of Next.js architecture is "Push Client Components to the leaves."
If your entire page is a Client Component, your entire page becomes interactive and ships its JS to the browser. Instead, keep your page and layout as Server Components, and only import the "interactive bits" (like buttons, forms, or carousels) as Client Components.
This minimizes the amount of JavaScript the user's browser has to download, which is a major factor in improving your Core Web Vitals.
Hands-on Exercise
- Open your project from Setting Up Your First Next.js Project.
- Create a
components/directory in your root. - Create a file named
Clock.jsinside it. - Use
useStateanduseEffectto display the current time. - Don't forget the
'use client'directive at the top! - Import and use this
Clockcomponent in yourapp/page.js.
Common Pitfalls
- Forgetting 'use client': If you try to use
useStateoruseEffectwithout the directive, Next.js will throw an error immediately. - Over-using 'use client': Don't mark a component as a Client Component just because it's a "component." If it doesn't need state or browser APIs, keep it a Server Component.
- Importing Server Components into Client Components: You cannot import a Server Component directly into a Client Component. Instead, pass the Server Component as
childrenor apropto the Client Component.
Frequently Asked Questions
Q: Can I use props in Server Components? A: Yes! You can pass data from a Server Component to a Client Component as props.
Q: Does 'use client' mean the component never runs on the server? A: No. It still renders on the server to produce the initial HTML, which helps with SEO and perceived load speed.
Q: How do I know if a component should be a Client Component?
A: If you need useState, useEffect, useContext, or browser-only APIs like window or localStorage, it must be a Client Component.
Recap
In this lesson, we defined the boundary between Server and Client components. We learned that Server Components are the default for performance, while Client Components provide interactivity via the 'use client' directive. By keeping Client Components at the "leaves" of our component tree, we ensure our Next.js apps stay fast and lightweight.
Up next: Building the Root Layout, where we will define our global HTML structure and metadata.
Work with me

Next.js Full-Stack Web App Development
A fast, SEO-ready full-stack web app built with Next.js 16 — from idea to deployed product, by an engineer who ships to production.

Next.js Website & Landing Page Development
A blazing-fast, SEO-optimized website or landing page in Next.js — the kind that loads instantly and ranks. Design-to-code, done right.