Server Components vs client Components

By default, every component in the App Router is a Server Component. It runs on the server, renders to HTML, and never ships to the browser. To make a component interactive (hooks, event handlers, browser APIs), you mark it as a Client Component with a use client directive at the top of the file.

app/books/page.tsx
tsx
// Server Component by default, no directive needed
export default async function BooksPage() {
  const res = await fetch('http://localhost:3000/api/books', {
    cache: 'no-store', // always fresh on every request
  });
  const books = await res.json();

  return (
    <main>
      {books.map((b: any) => <h2 key={b.id}>{b.title}</h2>)}
    </main>
  );
}

A Server Component. Fetches data directly, never hits the browser bundle.

app/components/AddToCartButton.tsx
tsx
'use client';

import { useState } from 'react';

export function AddToCartButton({ bookId }: { bookId: number }) {
  const [added, setAdded] = useState(false);

  return (
    <button onClick={() => setAdded(true)} disabled={added}>
      {added ? 'Added' : 'Add to Cart'}
    </button>
  );
}

A Client Component. The use client directive opts it in to the browser bundle.

The rule is simple. If a component uses useState, useEffect, event handlers, or any browser API, it needs use client at the top. If it does not, leave it as a Server Component and it never reaches the browser bundle. Mix the two freely: a Server Component can render a Client Component and pass props to it.

Quiz: Quiz

Loading practice…