← All lessons
Lesson 06 · Intermediate

Server & Client Components

Components default to running on the server. Learn when and how to opt into "client" with the "use client" directive.

Every component in the App Router is a server component by default. Server components render to HTML on the server, send that HTML to the browser, and ship no JavaScript for themselves. You only pay JS bandwidth for the components that need it.

When you need client

A component must be a client component when it uses any of these:

  • React state (useState, useReducer)
  • Effects (useEffect, useLayoutEffect)
  • Browser APIs (window, localStorage, IntersectionObserver)
  • Event handlers like onClick, onChange, onSubmit
  • React context (consuming it)

To opt a component into client mode, put a directive at the top of the file:

"use client";

import { useState } from "react";

export default function Counter() {
  const [n, setN] = useState(0);
  return <button onClick={() => setN(n + 1)}>Clicks: {n}</button>;
}

The directive is contagious — downward only

Once a file has "use client", every component imported from it is also a client component. But a server component can still import and render a client component freely. The boundary only flows one direction.

A common pattern is to keep most of the page on the server, and drop in small client islands where interactivity is needed:

// app/post/page.js  (server component)
import Counter from "./Counter";   // a client component

export default async function Post() {
  const post = await getPost();
  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
      <Counter />
    </article>
  );
}

What you cannot do

  • A client component cannot await a database call directly — it runs in the browser. Fetch in a server component above it, and pass data down as props.
  • You cannot pass non-serializable values (functions, class instances, Date is fine) from a server to a client component as props. Server actions are an exception — see lesson 13.
  • You cannot import a server-only module inside a client component.
Note: A useful rule: write everything as a server component, and only add "use client" when you hit something that needs it. Move the directive as far down the tree as possible.

Try it

This component uses `useState`. Make Next.js happy by marking it correctly.

Need a hint?

Add a "use client" directive on the very first line of the file.

Quiz

Pick the best answer. You only get one shot per question.

1. Which of the following requires a client component?

2. Can a server component render a client component?

3. Why is it preferred to keep components server-side by default?