Skip to content
Chapter 30Lesson 6

Quiz - The server / client boundary

Quiz progress

0 / 0

A teammate opens app/dashboard/page.tsx, sees a plain component with no directive at the top, and asks “so where does this run?” In an App Router project, what’s the correct read — and what does that let this file do?

It’s a Server Component (the default with no directive), so it can be async, await db.query(...) directly in its body, and read process.env secrets — none of which reach the browser.

It runs in both places by default; the directive only matters for performance tuning, so it could use useState and query the database in the same file.

It’s a Client Component until you add "use server" to opt it into server rendering.

A product page renders a grid of cards, each with an interactive <AddToCart /> button. A teammate adds "use client" to the top of page.tsx “so the buttons work.” Why does a senior push back, and what’s the fix?

That directive drags the page, the grid, and every card into the client bundle. Move "use client" down to AddToCart alone — only the smallest interactive leaf and its dependencies should ship as JavaScript.

It’s fine — "use client" on the page only affects the page component itself, so the cards stay Server Components automatically.

The real fix is to keep "use client" on the page but wrap each card in <Suspense> so the JavaScript loads lazily.

You want a Client Component <Tabs> (it animates, holds active-tab state) to display server-rendered article content inside each tab. Which arrangement actually works?

Render <Tabs> from a Server Component and pass the server-rendered article as children (or another prop slot) — a Client Component can receive server content it doesn’t import.

Inside Tabs.tsx, import the <Article> Server Component and render it directly — Client Components can import Server Components as long as they don’t pass them props.

Your lib/db/index.ts reads process.env.DATABASE_URL and opens a connection. Someone could one day import it from a "use client" file and silently ship the connection string to the browser. The directive convention alone won’t catch it. What’s the senior guardrail?

Add import 'server-only'; at the top of the file — if it ever reaches the client bundle, next build fails with an error pointing at the offending import chain.

Add 'use server'; at the top of the file so every export becomes server-bound and can’t be imported by a client file.

Add 'use client'; to the database file so the bundler knows to keep it out of server code.

A junior types "use clinet" at the top of a new interactive component. The build succeeds, the page loads, but useState throws at runtime in production. What happened, and what’s the habit that prevents it?

A typo’d directive is silently ignored — the file stayed a Server Component, so the hooks crash at runtime. Copy the directive from a known-good file instead of typing it by hand.

The directive must be all-lowercase with single quotes; double quotes like "use client" are what actually broke it.

"use clinet" was treated as a custom directive name; you fix it by registering it in next.config.js.

A Server Component renders a Client <Row> and tries to pass onDelete={() => deleteUser(user.id)}. The build errors with “Functions cannot be passed directly to Client Components.” Separately, the same page passes a user prop that’s an instance of a User class with methods. Which statements are correct? Select all that apply.

The callback fails because functions don’t cross the RSC wire; the fix is to define a "use server" Server Action and pass its reference instead.

The User class instance won’t cross either — flatten it to a plain object ({ id, name, email }) at the boundary; methods and the constructor don’t survive serialization.

Wrapping the callback in JSON.stringify() before passing it makes it serializable and crossable.

A Date field on user would fail the same way the class instance does, so dates must be passed as ISO strings.

A Client Component renders <span>{new Date().toLocaleString()}</span> to show the current time. It looks fine on first paint, then React throws “Hydration failed because the server-rendered HTML didn’t match the client.” What’s the root cause, and the default fix?

The timestamp differs between the server render and the browser render, breaking the strict-equality handshake. Render a stable placeholder on the server and set the real time in a useEffect after mount.

The component is missing a key prop, so React can’t match the server and client nodes; add a stable key.

Server Components don’t hydrate, so the fix is to remove "use client" and let it render on the server only.

Quiz complete

Score by topic