How would you set an organisation-wide policy for what gets seeded into the page versus fetched by the browser?
answer
- ownership, volatility, size, first paint
- a default makes exceptions visible
- personal values out of shareable artifacts
- budget the serialised bytes
- diff payloads across two identities
basics
~20 sDecide it on four axes: who the data belongs to, how fast it goes stale, how big it is, and whether the first screen needs it. Publish that as a default with a byte budget and a payload review.
solid answer
~40 sTeams should not relitigate this per feature. State a default: **seed what the first screen renders, fetch what an interaction needs, and keep anything personal out of a shareable artifact.** Then name the axes that justify an exception — ownership (shared versus per-user), volatility, payload size, and whether the first paint depends on it. Attach two limits that make the default enforceable: a budget on serialised bytes per document, and a rule that any route whose seed contains personal data is non-shareable and reviewed. The point of a written default is reviewability: a reviewer can only spot a dangerous exception if there is a norm to compare against. Measure it rather than trusting it — diff payloads across two identities on personalised routes, and track seed bytes alongside the other page-weight numbers.
go deeper
The takeaway is that this is a decision with rules, not a per-component reflex: what the first screen shows travels with the page, and what the user might click is fetched when they do.
Be able to name the axes — ownership, volatility, size, first-paint dependence — and say which way each pushes, rather than defending one habit for every read.
Show the operational side: a stated default so exceptions are reviewable, a budget on serialised bytes, and a check that reads the delivered payload instead of trusting the code.
Order the concerns explicitly — safety, then user-visible benefit, then cost — and describe how the policy is enforced in shared code and measurement rather than in a document nobody rereads.
At one page this is a design decision. Across dozens of teams it is a policy question, because the failure modes are not evenly distributed: the cost of over-seeding lands on page weight and on a leak surface nobody owns, while the cost of under-seeding lands on the very user experience the server render was adopted for. ## The axes a policy has to name - **Who the data belongs to.** Shared and impersonal, or specific to one user? This axis decides safety, not performance, and it outranks the others. A per-user value inside an artifact that may be stored or reused is a defect regardless of how much faster it makes the page. - **How fast it goes stale.** A snapshot that is wrong within seconds is not worth serialising; one that changes per deploy can be trusted for the life of the page. - **How big it is.** Seeding duplicates values that the markup may already carry. A list of thousands can cost more in document bytes and parse time than the round trip it saves. - **Whether the first screen depends on it.** Data behind an interaction is not first-paint data, and loading it during the render makes every response slower to serve a minority of sessions. - **Who will refresh it, and when.** If the client is going to revalidate the value immediately anyway, the seed is weight with no benefit. ## A default worth writing down 1. **Seed what the first screen renders**, projected down to the fields that are actually displayed. 2. **Fetch in the browser what is personal, live, or deferred** behind an interaction. 3. **Never let a personal value enter a shareable artifact** — the route either carries no personal seed, or it is marked private and excluded from prerendering and reuse. A default is not a ban. Its value is that it makes deviations visible: a reviewer who sees a route seeding a thousand rows, or a personal value on a shareable route, has a stated norm to point at instead of an argument about taste. ## The two failure modes of an unset policy | Extreme | What it looks like | What it costs | |---|---|---| | Seed everything | fat documents, entities serialised whole, personal data in reusable artifacts | transfer and parse time on the critical path, a leak surface that grows silently, snapshots that age badly | | Seed nothing | every read fetched after load, loading states over rendered content | the server render's benefit is spent, per-component request chains reappear, more requests per session | Neither extreme is chosen deliberately; both are what an unstated policy converges to depending on which team's habits dominate. ## Making it hold without a gatekeeper - **Set defaults in shared code, not in a document.** A shared data-access helper that requires an identity in the key for identity-dependent reads enforces more than a paragraph on a wiki ever will. - **Budget serialised bytes.** Track payload size per route alongside other page-weight numbers, and fail the build or flag the review when a route crosses the line. - **Make personalisation an explicit, visible property of a route.** If whether a route is shareable is discoverable at a glance, review can check it; if it is implied by which functions the render happens to call, it cannot. - **Test at two identities.** The cheapest real check is requesting a personalised route as two accounts and diffing the delivered payloads; identical bytes is the bug, and it catches the whole class without anyone reasoning about caching. ## What you actually measure - **Requests in the first seconds after load.** A page that seeds well should be quiet; a staircase of requests after interactivity means first-screen data is still being fetched. - **Serialised payload bytes per route, tracked over time.** Growth here is silent, incremental, and nobody's ticket. - **Payload diffs across identities on personalised routes**, run continuously rather than at review time. The answer that distinguishes a lead is the ordering: safety first (ownership decides what may be seeded at all), then user-visible benefit (first-screen data earns its bytes), then cost control (everything else is fetched on demand) — and a statement of how the policy is kept honest once written, because a default nobody measures decays into whatever the last busy sprint produced.
- Which axis do you resolve first when two of them conflict?Ownership. If the value is personal, it must stay out of any artifact that can be stored or reused, whatever it would do for first paint or request count. Performance arguments are made inside that constraint, never against it.
- How do you keep the policy from decaying once it is written?Put it where it is enforced rather than where it is read: shared data-access helpers that require identity in the key, a tracked budget on serialised bytes per route, a visible per-route shareability flag, and a continuous two-identity payload diff. A guideline nobody measures reverts to whatever the last deadline produced.
- What is the honest cost of a strict 'seed everything the page might need' rule?Documents grow with entities serialised whole, transfer and parse time land on the critical path, snapshots age badly in long-lived tabs, and the exposure surface expands with every field nobody renders. It also hides the personal-data question behind a habit, which is where the real incidents come from.
saying these in an interview costs you the question
- Treats it as a per-feature judgment with no stated default.
- Optimises for speed before deciding who the data belongs to.
- Seeds whole entities and trims the fields in the component.
- Assumes a written guideline holds without measurement or shared defaults.
- Bans browser-side fetching outright to keep pages fast.