skip to content

A team has made every route in their Next.js App Router app render on each request because it is simpler and always fresh. As the engineer leading the app, how do you evaluate that default and decide which routes to pull back to static or revalidated rendering?

level: principalimportance: should knowfreq 38%

answer

  1. concede the safety, price the cost
  2. cost, latency, resilience, elasticity
  3. requester-dependence, staleness, traffic share
  4. staleness budget comes from product
  5. convert the top routes, then measure

basics

~20 s

Treat it as a cost and resilience decision, not a style preference. Inventory routes by whether output depends on the requester, their freshness tolerance and their traffic share, then convert the highest-traffic request-independent routes first and measure the change.

solid answer

~50 s

I would not argue the default is wrong in principle — it is uniform and it never serves the wrong user's data, which are real virtues. I would argue it is unpriced. Rendering every route per request means server cost scales linearly with traffic, every page's time to first byte inherits its slowest upstream call, and a traffic spike or an upstream outage reaches users directly instead of being absorbed by cached output. So I would price it: rank routes by traffic, mark which ones genuinely vary per requester, and get an explicit staleness tolerance in seconds for the rest from product rather than from engineers. The request-independent, high-traffic routes convert first, since they carry the most cost and the least risk. Then I would measure before and after — latency percentiles, origin request volume, behaviour under a synthetic upstream failure — and stop converting when the remaining routes are low-traffic or genuinely need per-request correctness.

go deeper

for a junior

Understand that rendering per request costs server work on every visit, and that pages identical for all visitors do not need to pay it.

for a middle

Be able to classify routes yourself — which vary per requester and which do not — and explain what a page gives up by rendering per request.

for a senior

Demonstrate the measurement and the sequencing: rank by traffic, convert the biggest request-independent routes first, and prove the change with latency and origin-volume data.

for a principal

Own the framing that rendering mode is a per-surface freshness-versus-availability contract, get the staleness budget from product, and leave behind a review practice so the decision stays explicit as the app grows.

## Start by conceding the good part A lead who opens with "dynamic everywhere is wrong" loses the room. It has genuine advantages: one mental model, no cache-invalidation class of bug, and no possibility of serving a personalized page to the wrong person. Those are the failure modes that produce incidents, and the team chose to eliminate them. The correct critique is narrower — the choice was made *by default rather than by decision*, and its costs are invisible because nobody has priced them. ## What the default actually costs Four axes, and it helps to name them separately because they fail differently. **Cost.** Server work scales one-to-one with page views. A route serving identical HTML to a million visitors runs a million renders. Whether that shows up as compute spend or as capacity you must keep provisioned, it is a line item that grows with success. **Latency.** A per-request render cannot finish before the slowest thing it awaits. Every upstream dependency is now on the critical path of every visit, and time to first byte is bounded below by the p99 of the worst call. Prerendered output moved those calls off the request path entirely. **Resilience.** This is the argument that lands hardest and gets raised least. When the product API is down, a route with stored output keeps serving the last good page; a per-request route serves an error. Rendering mode is therefore a availability decision for the pages that matter most — the ones you would rather show slightly stale than not at all. **Elasticity.** Traffic spikes are the case where the two diverge most sharply. A campaign, a link from a big account, a crawler sweep — cached output absorbs it, per-request rendering forwards the whole shape of it to your backend. ## The inventory I would build a small table before touching any code, with one row per route and three columns. 1. **Does the output depend on the requester?** Signed-in state, cookies, geo, search params. If yes, the route stays dynamic — this is not negotiable and is where the team's instinct was right. 2. **What staleness is tolerable, in seconds?** Ask product, not engineering. Engineers answer "as fresh as possible" because staleness has no cost to them; product owners can tell you that a marketing page may be an hour old and a stock indicator may not be five seconds old. 3. **What share of traffic does it carry?** This orders the work. Converting a route nobody visits changes nothing. The rows that are request-independent, staleness-tolerant and high-traffic are the conversion list, in that order. Usually it is a handful of routes — a landing page, a catalogue index, a docs or article tree — carrying a large fraction of total volume. ## Sequencing and proof Convert the top one or two first, and instrument it. What I want to see: origin request volume for that path dropping toward zero, time to first byte losing its long tail, and no increase in complaints about stale content. Then rerun a synthetic upstream failure and confirm the converted route still serves while the dynamic ones degrade. That evidence, on a route the team cares about, does more to settle the argument than any amount of reasoning about theory. Where the freshness tolerance is short but nonzero, revalidated prerendering is the middle ground — you keep cached economics and bound how old the page gets. Where the tolerance is genuinely near zero and the page is still identical for everyone, dynamic rendering is the right answer and should be recorded as a decision, not an accident. ## What I would institutionalize The durable outcome is not a set of converted routes; it is that rendering mode becomes an explicit property of each surface. Concretely: a stated staleness budget per route in the same place the team documents ownership, a review question for new routes asking which mode and why, and a check on the build output so a route silently flipping to dynamic is noticed at review time rather than in a bill. ## Where I would stop I would resist converting the long tail. The cost curve is dominated by the top routes, and each conversion adds an invalidation path somebody has to maintain. Leaving low-traffic and genuinely request-dependent routes dynamic keeps the mental model simple where it does not cost anything — which is, in the end, agreeing with the team's original instinct in the places where it was right.

  • Which single argument tends to move a sceptical team fastest?
    Resilience, demonstrated rather than described. Take the top route, convert it, then simulate the product API failing and show that the converted page still serves last-known-good content while the dynamic ones return errors. Cost arguments get deferred to next quarter; an availability demo on a page the team owns changes the default in the next sprint.
  • How do you stop routes from silently drifting back to per-request rendering?
    Make the mode visible and reviewed. Next's build output already reports which routes are static and which are dynamic, so the drift is observable; I would surface that in CI and treat a change in a route's mode as something a reviewer must acknowledge, the same way a new dependency or a schema change is acknowledged.
  • When would you defend leaving a high-traffic, request-independent route dynamic?
    When its correctness window is genuinely shorter than the render cost — a live availability or pricing figure where showing a stale number causes real harm. At that point caching buys you complexity for negligible staleness reduction, and the honest answer is to render per request and invest in making the underlying query fast instead.

saying these in an interview costs you the question

  • Declares dynamic rendering simply wrong without pricing it
  • Proposes converting every route at once with no ordering
  • Asks engineers, not product, how stale a page may be
  • Ignores that some routes must stay per-request for correctness
  • Argues only about cost and never about availability under upstream failure

context