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.
// 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.
'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…