Fullstack CourseLearn by building
Back to week 3

Topic

Choose Server and Client Components

Definition

React Server Components render on the server and do not send their component implementation to the browser; Client Components opt into browser JavaScript for state, effects, and event handlers.

In simpler words

Server is the default. Add use client only around the smallest interactive part.

The boundary controls bundle size, available APIs, and whether code can safely access server-only values.

After this you can

  • Recognize browser-only code
  • Place a client boundary low in a component tree
  • Explain why Client Components cannot import server-only modules

Start on the server

A Server Component can read server-only configuration, await rendering data, and compose Client Components. Its component code is not shipped as a browser bundle just because it renders JSX.

State hooks, effects, event handlers, and browser APIs such as window require a Client Component. The use client directive marks a module boundary, so its imports become part of the client graph too.

Keep the interactive leaf client-side

// TicketPage.tsx — Server Component by default
export default function TicketPage() {
  return <><TicketSummary /><TicketFilters /></>;
}

// TicketFilters.tsx
'use client';
export function TicketFilters() {
  const [open, setOpen] = useState(false);
  return <button onClick={() => setOpen(!open)}>Filters</button>;
}

Only the filter control needs browser JavaScript.

Mistake: making the whole page client-side

// Wrong — all imports below become client-bundle candidates
'use client';
export default function TicketPage() { return <TicketList />; }

// Right — keep the page server; isolate the interactive child

A high boundary increases JavaScript and blocks server-only imports.

Respect the import boundary

Definition

A Client Component cannot import server-only modules, secrets, database code, or code that depends on server runtime APIs.

In simpler words

Pass serializable data from a Server Component into a Client Component instead.

The directive is not an instruction to render only in the browser; Client Components can still be pre-rendered.

Move a client boundary downward before adding one to a page or layout.

Live playground

Server and Client Components playground

Move use client between a page and button, then identify what ships to the browser.

Can fetch on server; cannot use useState/onClick.

Keep in mind

  • Default to Server Components.
  • Put use client on the smallest interactive leaf.
  • Treat a Client Component’s imports as browser-visible code.

Test

Check your understanding

At least 10 questions — mix of concept, syntax, practical, and logic. Score ≥80% (enforced by the API) to save progress.

Checking your session…

15 questions · concept 5 · syntax 3 · practical 4 · logic 3

1. Default for App Router components?
Concept
2. When add 'use client'?
Syntax
3. Can Server Components use useState?
Practical
4. Why Server Components help?
Logic
5. Passing server data to client children?
Concept
6. Where do event handlers live?
Practical
7. Composition pattern?
Syntax
8. Can Client Components import Server Components?
Logic
9. Secrets in Server Components?
Concept
10. Which statement is true?
Practical
11. What kind of component is this by default?
Conceptintermediate
// app/page.tsx (no directive)
export default function Page() { return <h1>Hi</h1>; }
12. Why is the "use client" directive needed here?
Syntaxintermediate
'use client';
export default function Counter() {
  const [n, setN] = useState(0);
}
13. Why does this Server Component fail?
Practicaladvanced
// Server Component
export default function Page() {
  const [open, setOpen] = useState(false);
}
14. What is risky about passing onClick here?
Logicadvanced
// Server Component passing to a client child
<Chart data={rows} onClick={handleClick} />
15. Why is fetching directly here acceptable?
Conceptintermediate
export default async function Page() {
  const data = await db.tickets.findMany();
  return <List items={data} />;
}

Checking your session…