Immediate snapshot
Browser-readable markup for the initial load. It may be prerendered or request-rendered using output from both Server and Client Components. It is not the RSC payload.
Lesson 04 · Advanced frontend rendering
Estimated time: about 14 minutes
RSC is not another word for SSR. It partitions the module graph: some component code executes only in a server environment, while explicit client entry points ship for interaction.
An RSC framework may send all three on an initial visit. Treating them as one thing makes performance and debugging conversations fuzzy.
Browser-readable markup for the initial load. It may be prerendered or request-rendered using output from both Server and Client Components. It is not the RSC payload.
A serialized representation of Server Component output, Client Component references, slots, and serializable props. React uses it to reconcile the combined tree.
The module graph below client entry points. It hydrates Client Components and supports later browser state and events. Server Component source is absent.
Run in the framework’s server environment at build time or request time. They may await data and use server-only dependencies, but cannot hold browser state or event handlers.
Belong to the client module graph and can use state, effects, context, handlers, and browser APIs. On an initial visit, a framework may still use them while producing HTML.
Async server endpoints referenced from client code, often for mutations. 'use server' marks these functions—it does not mark a Server Component.
An optional HTML-generation step. Server Component output can be SSR’d, prerendered at build time, streamed, cached, or requested during client navigation.
'use client' marks a module entry point and its transitive dependencies for client evaluation. It is not a label that affects only the component function in that file.
Boundary at ProductPage
Observe which modules become browser code.
8 modules in the illustrative client graph.
Invalid graph: the browser subtree now reaches a server-only database module.
A Server Component can render a Client Component and pass supported serializable values across the boundary.
The client module graph cannot execute a Server Component module. Compose it in a server parent and pass its rendered element through a slot such as children.
Values passed into a Client Component are serialized for the browser. Server access is safe; sending secrets or excess records as props is not.
Context requires a Client Component. Wrap only the subtree that consumes it so unrelated modules and static work remain outside the client boundary.
// Server Component
export default async function ProductPage({ id }) {
const product = await db.product.find(id);
return (
<ProductView description={product.description}>
<Gallery images={product.images} /> {/* client */}
<CartButton productId={product.id} /> {/* client */}
</ProductView>
);
}
| Claim | Correction |
|---|---|
| “Client Components only render in the browser.” | They ship to the browser, but an RSC framework can also use them to produce initial HTML before hydration. |
| “Server Components require a live server.” | They may execute during the build and produce static output; “server” names the environment, not necessarily request timing. |
“Add 'use client' wherever hooks appear.” | Add it at client entry points. Modules already below that boundary are client modules without repeating the directive. |
“'use server' marks a Server Component.” | There is no Server Component directive. 'use server' exposes an async Server Function reference. |
| “Server code means secrets are automatically safe.” | Imports can remain server-only, but props and Server Function results are serialized. Authorize inputs and minimize returned data. |
| “RSC removes waterfalls.” | It removes some client round trips and colocates reads, but sequential server awaits can still waterfall. Start independent reads in parallel and stream useful boundaries. |
Scenario: A product route fetches from a database, parses Markdown, formats a localized price, renders an image gallery with swipe state, and includes an optimistic add-to-cart control. Where should the client boundary start?
Choose first. Then name the server-only imports, serialized props, browser capabilities, and transitive modules on each side.
“RSC and SSR solve different problems. RSC partitions execution and defines a serialized component payload; SSR turns the initial combined tree into HTML. I can use RSC at build time or request time, with or without streaming and caching.”
“I’d keep the route, database query, Markdown parser, and price formatter in the server graph. Gallery and cart are separate client entry points because they need browser state and events. I’d pass narrow serializable props rather than the entire ORM object.”
“I’d inspect the client module graph, RSC payload size, serialization cost, server render latency, data-fetch parallelism, hydration work, cache behavior, and navigation traces. A smaller client bundle can still be offset by slow or over-dynamic server work.”
'use client' — module graph boundaries, transitive dependencies, and supported serialized values.