skip to content

Server-Only Code Isolation

How data access, credentials and heavy dependencies stay out of what ships to the browser, and how that split is declared. Interviewers probe where you draw the line and what the wrong side costs.

on this pageshow

questions

5

In a meta-framework that renders on the server and ships JavaScript to the browser, which code must stay server-only?

level: juniorimportance: must knowfreq 72%

answer

  1. one source tree, two outputs
  2. reachability decides, not intent
  3. follow imports from the client entry
  4. credentials and data access never cross

basics

~20 s

Credentials, direct data-store access, internal service addresses and dependencies used only to build markup stay server-only. Anything a client entry point can reach by import is downloaded by the browser, so those modules must never appear in that import chain.

solid answer

~50 s

The split is about **reachability**, not intent. A meta-framework compiles one source tree twice — once for the side that produces the response, once for the browser bundle — and any module reachable by import from a client entry lands in the bundle. So server-only means anything whose presence in a download is either a disclosure or a waste. Disclosure covers API keys, data-store credentials and the access code that uses them, internal hostnames, and rules a user should not be able to read such as pricing or fraud heuristics. Waste covers heavy render-time dependencies — a markup renderer, a syntax highlighter — where the server uses the tool and the browser only needs the result. Code has to move to the client only when it must handle events, keep state in the page, or use a browser API; everything else can stay behind.

go deeper

for a junior

Be able to name the categories that never ship: credentials, data-store access, internal addresses, and dependencies used only to produce markup. Say plainly that whatever the browser downloads is readable by anyone.

for a middle

Explain the reachability rule — a module lands in the browser bundle because something in the client entry's import chain imports it — and why a runtime environment check changes what executes, not what is compiled.

for a senior

Show that you treat a bundle leak as an incident. Shipped builds were downloaded and cached, so the response is rotation plus a build-time guard that prevents the next one, not a quiet redeploy.

for a principal

Frame it as trust-boundary design: decide which privileged operations exist at all, funnel them through a few auditable modules, and accept that any capability exposed to the browser becomes a public surface you must defend.

## One source tree, two outputs A meta-framework compiles a single project into at least two artefacts: code that executes while a response is being produced — on a server, during a build step, or both — and a bundle of JavaScript that the browser downloads and runs. Because both come from the same files, "where does this code live?" has a precise mechanical answer, and it is usually not the one people assume. A module ends up in the browser bundle when it is **reachable by import** from a client entry point. Not when it is *called* in the browser; not when it sits in a particular folder; not when a comment above it says otherwise. ## The reachability rule in practice The chain is what matters, and it has several shapes: - **Direct import** — a client module imports the sensitive module by path. Obvious, and the rarest cause of real incidents. - **Transitive import** — a client module imports a shared helper, and that helper imports the data-access module. Distance does not weaken the chain. - **A re-export barrel** — an index module that gathers and re-exports a folder. Importing one wanted symbol from it can drag in everything it re-exports. - **A type reference written as a value import** — types erase at compile time only when the import is declared type-only; otherwise the runtime module travels with it. - **A constant inlined at build time** — the function body may be eliminated while the literal it closed over survives in the output. ## What must stay behind | Category | Examples | What shipping it costs | |---|---|---| | Credentials | API keys, data-store passwords, signing keys, private tokens | Direct compromise; the value is public the moment the build is served | | Privileged access code | drivers, connection pools, query builders, admin clients | Discloses schema and internal query shapes, and usually carries a credential too | | Internal topology | service hostnames, admin endpoints, queue names | Reconnaissance: it maps what sits behind the perimeter | | Rules a user should not read | pricing logic, fraud heuristics, thresholds | Gameable logic and disclosed intent | | Render-only dependencies | markup renderer, syntax highlighter, large formatting tables | No disclosure, just bytes: download, parse and memory the user never needed | The last row is the one people forget. It carries no secret, so nothing alarming happens when it leaks — the user simply pays for a tool whose *output* was the only thing they needed. ## What legitimately has to ship The pressure runs the other way too. A unit must be in the browser when it has to respond to a user event, keep state that survives across renders inside the page, or touch a browser-only API such as the document, storage or the clipboard. Everything else *can* stay on the server side. Whether it *must* is the disclosure question above, and the two decisions are separate: "needs to be interactive" and "is safe to publish" are not the same predicate. ## Why "it never runs in the browser" is not a defence A runtime environment check changes what **executes**, not what is **compiled**. A bundler removes code only when it can prove that code unreachable and free of side effects. A module that opens a connection, registers a handler, or reads configuration at import time cannot be dropped safely, and a re-export barrel defeats the analysis outright. The working assumption should be: if client code can reach it by import, assume it shipped — then verify against the built output rather than against intent. ## What a leak actually costs Shipped JavaScript is public by construction. Minification renames identifiers; it does not conceal string literals, and source maps are frequently deployed alongside the bundle. A build that was served has been downloaded by browsers, cached by intermediaries, and possibly archived by third parties. Removing the value and redeploying therefore undoes nothing: the remediation for a disclosed credential is **rotation**, plus a look at whether it was used in the window it was exposed. Some leaks cannot be rotated at all. An internal hostname or a query shape is not a value you can reissue — it can only be re-architected. That asymmetry is the argument for drawing the line categorically rather than case by case. ## How the split is made real 1. **Declare** the split explicitly — through a naming or directory convention, a fenced server-only section of a route module, an explicit marker that opts a module into the client bundle, or by declaring only the interactive parts of the page. 2. **Guard** it at build time, so a violating import fails the build and names the chain that caused it, instead of producing a bundle nobody inspects. 3. **Verify** against the built artefact — search the client output for a known canary string before it ships, because the first two steps only cover what they were applied to. Isolation is a property of the import graph, enforced by the build. Every convention above it is a way of making that property easy to state and hard to break by accident.

  • If a server-only module is imported by client code but the value it exports is never used, does it still ship?
    Usually yes. A bundler drops code only when it can prove it unreachable and free of side effects, and a module that opens a connection or reads configuration at import time cannot be dropped safely; a re-export barrel defeats the analysis entirely. Treat any import from a client graph as shipped until the built output proves otherwise.
  • Does keeping a key out of the bundle protect it if the browser calls an endpoint that uses that key?
    Yes for the key, no for the capability. The value stays secret, but the endpoint is now a public surface acting with that key's privileges, so it needs its own authentication, authorisation and rate limiting. Isolation moves the trust boundary; it does not remove the need to defend what sits behind it.

saying these in an interview costs you the question

  • Thinks minification hides an API key in shipped JavaScript.
  • Assumes a module is safe because nothing on screen renders it.
  • Believes a runtime check for the browser keeps a dependency out of the bundle.
  • Treats the split as purely a performance concern and never a disclosure one.
  • Thinks a leaked credential is fixed by redeploying a build without it.
open as a page

How do meta-frameworks let you declare which modules are server-only, and what invariant do those schemes share?

level: middleimportance: must knowfreq 58%

basics

~20 s

Meta-frameworks use file or directory naming, a fenced section of the route module, an explicit opt-in marker for client modules, or islands that declare only interactive parts. All enforce one invariant: nothing a client entry imports may reach server-only code.

open as a page

What does a build-time server-only guard give you that a naming convention plus code review does not?

level: middleimportance: should knowfreq 50%

basics

~20 s

It fails the build whenever a protected module is reached from a client entry point, and names the import chain that did it. Review catches direct imports; the guard also catches the transitive ones introduced later.

open as a page

A module that reads a private key turns up in your shipped browser bundle. How do you find the import that pulled it in, and what else does the leak require?

level: seniorimportance: should knowfreq 55%

basics

~20 s

On a production build, ask the bundler why that module is included and walk the chain back to the client entry; the cause is usually a re-export barrel or a helper. Then rotate the key, because that build was served.

open as a page

Your team keeps server-only code out of the browser by convention alone. How would you decide what enforcement to add?

level: principalimportance: should knowfreq 42%

basics

~20 s

Rank by blast radius. Put a build-time guard on the few modules holding credentials or privileged access, leave conventions for the rest, and keep output scanning and key rotation as the detection and recovery layers.

open as a page