Lesson 04 · Advanced frontend rendering

Server Components split the program

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.

14 minPayload + boundary lab

Three artifacts, three jobs

An RSC framework may send all three on an initial visit. Treating them as one thing makes performance and debugging conversations fuzzy.

1 · HTML

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.

2 · RSC payload

Tree instructions

A serialized representation of Server Component output, Client Component references, slots, and serializable props. React uses it to reconcile the combined tree.

3 · Client JavaScript

Interactive code

The module graph below client entry points. It hydrates Client Components and supports later browser state and events. Server Component source is absent.

The execution model

Server Components

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.

Client Components

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.

Server Functions

Async server endpoints referenced from client code, often for mutations. 'use server' marks these functions—it does not mark a Server Component.

SSR

An optional HTML-generation step. Server Component output can be SSR’d, prerendered at build time, streamed, cached, or requested during client navigation.

Move the boundary, move the graph

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

ProductPageorchestration
product-querydatabase import
Markdowndescription parser
ProductViewstatic layout
Priceformatting
Galleryswipe state
CartButtonoptimistic state
analyticsbrowser events
Server graph Client graph

8 modules in the illustrative client graph.

Invalid graph: the browser subtree now reaches a server-only database module.

Composition rules that matter

Server imports Client: yes

A Server Component can render a Client Component and pass supported serializable values across the boundary.

Client imports Server: not directly

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.

Props cross a public wire

Values passed into a Client Component are serialized for the browser. Server access is safe; sending secrets or excess records as props is not.

Providers belong deep

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>
  );
}

Interview traps

ClaimCorrection
“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.

Boundary drill

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?

A senior-shaped interview answer

“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.”

Primary reading