skip to content

You are reviewing a React 19 app that uses Server Components. For each of these, say whether it belongs in a Server Component or a Client Component and why: (1) calling an internal API with a key read from an environment variable; (2) formatting values with a 180 kB internationalisation library into static text; (3) a modal whose open/closed state toggles on a button press; (4) re-sorting a 5,000-row table when the user clicks a column header.

level: seniorimportance: should knowfreq 48%

answer

  1. ask who needs the browser to work
  2. does this code have to ship at all
  3. secrets and heavy deps stay server
  4. state or handler means client
  5. some cases turn on shareable URLs

basics

~20 s

The secret-bearing call and the heavy formatting belong in Server Components, because that code never ships to the browser. The modal toggle and the click-driven table sort need state and event handlers, so they must be Client Components.

solid answer

~50 s

One and two are server work. The API key call must stay on the server because a Server Component's module is never sent to the browser, so the credential is never exposed; the 180 kB formatter is server work because only its *output* — plain text — needs to reach the user, and keeping it server-side removes those bytes from the bundle entirely. Three is client work without argument: an open/closed flag that changes on a press needs a live instance in the browser to re-render. Four is the interesting one. If the sort must feel instantaneous with no round trip, it is client state on a Client Component. If the ordering is really part of the request — a URL parameter your framework re-renders on — the sort can stay server-side and only the header link is interactive. The general test: does it need state, a handler, a ref, or a browser API? Client. Does it need private resources or heavy dependencies whose output is static? Server.

go deeper

for a junior

Practise the basic sort: anything with state, a click handler, or a browser API is a Client Component; data reading and static markup are Server Components.

for a middle

Justify each call with a mechanism — secrets stay safe because the module never ships, and a render-only dependency costs nothing client-side when only its text output crosses.

for a senior

Commit to a decision on the ambiguous case and name the condition that would reverse it: data volume, whether the ordering should be shareable, and how much latency the interaction can absorb.

for a principal

Set the team's default and the exceptions: server-first with client scoped to the smallest interactive unit, plus a way to verify bundle claims in CI so the reasoning does not silently drift from the build output.

## The sorting test This is the question the model actually gets used for, and interviewers ask it with their own feature list. You want a repeatable test rather than case-by-case intuition: **Client if it needs the browser to work.** State that changes after load, an event handler, a DOM ref, a browser API (`window`, `localStorage`, `IntersectionObserver`), a subscription to something live. **Server if it needs the server, or if shipping it would be waste.** Privileged data access, secrets, direct database or filesystem reads, and any dependency whose only job is to turn data into markup or text. Ambiguous cases resolve on a second question: *does the result have to change without a round trip?* If yes, client. If it can change as part of a new request, server is cheaper. ## (1) The API key — server This one is not a preference; it is a correctness and security call. A Server Component's module is never sent to the browser, so an environment secret read there stays there. Move the same call into a Client Component and you have shipped the credential to every user, because the client bundle is fully readable. Say the mechanism out loud in an interview: the protection comes from the code not being in the bundle. Do not claim the framework "hides" the value at runtime — the value simply never travels. ## (2) The 180 kB formatter — server The component produces text. Text is cheap to send; the library that produced it is not. Rendering on the server means the user downloads the formatted strings and none of the formatting code. Two caveats worth naming yourself, because a good interviewer will: - If the output depends on something only the browser knows — the user's locale from `navigator.language`, their timezone — the server needs that as input, and if it cannot get it, some of the work has to move client-side. - The saving only materialises if no Client Component also imports that library. A shared module pulled in below a client boundary drags the dependency into the bundle anyway, so verify against the actual build output rather than the mental model. ## (3) The modal toggle — client A boolean that flips on a press, causing a re-render, is the textbook Client Component. There is no argument for the server side: the value has no meaning during the server render, and nothing on the server could change it. The interesting part is scope, not classification. The *toggle* is client; the modal's contents may well be server-rendered markup handed down as children, so a large static body does not have to become client code just because a button opens it. ## (4) The 5,000-row sort — it depends, and that is the point Here you are being tested on judgment rather than recall. Both answers can be right: **Client**, if the interaction must be instant and the data is already in the browser. Sorting an array of 5,000 rows in memory is fast; a round trip is not. The cost is that the rows had to be shipped as data and the table became client code. **Server**, if the ordering is genuinely part of what the page *is* — a sort that belongs in the URL, is shareable and bookmarkable, and pairs naturally with pagination. Then a new request re-renders the table server-side, and the only client code is whatever makes the header clickable. The deciding factors: how much data would have to ship to sort in the browser, whether the ordering should be shareable, whether sorting is coupled to pagination or filtering that already lives server-side, and how much latency the interaction can absorb. If the dataset is large enough that shipping it is the real cost, server-side ordering wins on bytes even though it costs a round trip. If the table is already in the browser for other reasons, sorting it there is free. ## What weak answers look like - Classifying everything as client because "it's a UI, users interact with pages." The unit of decision is the component, not the page. - Treating bundle savings as automatic without checking whether the dependency is also imported client-side. - Missing that the secret case is categorical while the others are tradeoffs. - Refusing to commit on the sort. The interviewer wants a decision plus the condition that would flip it, not a shrug. ## The summary line to land on Server by default; move to client at the smallest scope that genuinely needs the browser; and treat secrets and heavy render-only dependencies as reasons to stay server-side even when the client would technically work.

  • A teammate argues that making everything a Client Component still works, so the split is not worth the trouble. How do you answer?
    It works, but you pay three ways: every module below the boundary ships and runs in the browser, privileged data access and secrets can no longer live in the component, and data needs an extra network hop instead of being read where it lives. Server-by-default is the cheaper baseline; client is the deliberate exception you justify per component.
  • How would you verify that the heavy formatting library actually stayed out of the client bundle?
    Check the build output rather than trusting the reasoning — a bundle analysis of the emitted chunks tells you which modules landed client-side. The usual surprise is a shared utility module that a Client Component also imports, which pulls the dependency across the boundary along with it.
  • For the table, what would make you choose server-side sorting even though the interaction gets slower?
    Data volume and shareability. If sorting in the browser means shipping the whole dataset, the bytes cost more than the round trip. And if the ordering should be bookmarkable, or is already coupled to server-side pagination and filtering, keeping it in the request keeps one source of truth instead of two.

saying these in an interview costs you the question

  • Puts the API key in a Client Component and calls it safe
  • Keeps a render-only library client-side for no reason
  • Assumes a modal's open flag can live server-side
  • Says every sort must be client-side to feel fast
  • Marks whole pages client because users interact with them

context