One Application, Five Rendering Strategies
The same product built five ways, laid out on one shared scale so the trade-off is visible rather than argued. None of these wins. Each one moves work between the server and the browser, and every position on that curve buys something and gives something up.
The horizontal axis is relative units on a shared scale, not milliseconds. A real number would depend on a device, a network, a payload and a framework that this comparison does not have, and would be wrong for every reader in a different way. What is comparable — and what actually decides the choice — is the order the milestones arrive in, and the gap between content appearing and the page answering an input.
Shared scale, relative units. A bar reaching further right is later relative to the other four, and means nothing on its own.
What each one actually costs
Read the pair of columns together — what ships and when it answers an input are the same decision seen twice.
The application, its framework runtime and everything the route imports — as one gate in front of first content.
The bundle has executed and the data it then requested has arrived. Content and interactivity land together, at the end.
- — Applications behind a login, where the first view is personal and cannot be cached or pre-rendered anyway.
- — Long sessions where one slow entry is amortised across hundreds of instant client-side navigations.
- — Highly interactive tools — editors, canvases, consoles — where almost every pixel needs script regardless.
- — Teams shipping to a CDN with no server runtime, where every alternative requires infrastructure they do not have.
- — Anything that must be readable without JavaScript: search crawlers, link previews, a text browser, a device where the bundle failed to load.
- — First-visit experiences on slow devices, where parse and execute dominate and the blank page lasts as long as they do.
- — Content pages, where the entire payload exists to render text that could have been in the HTML.
- — Users on high-latency connections, who pay two dependent round trips before seeing anything.
The same application bundle as CSR, plus the serialised data embedded in the document.
The full bundle has downloaded, parsed and hydrated the entire tree — regardless of how little of the page is actually interactive.
- — Pages whose content is personalised or changes per request, so it cannot be built ahead of time.
- — Anything that must be indexable or shareable with content in the initial response.
- — First visits on slow devices, where painting text does not have to wait for a bundle to execute.
- — Cases where the server is close to the data and the client is not.
- — Pages where the server data fetch is slow — the whole document waits on the slowest query before anything is sent.
- — Mostly-static content, which pays per-request rendering for output that is identical every time.
- — Applications with a large bundle, where the gap between visible and interactive is long enough that people click into nothing.
- — Deployments with no server runtime, or where per-request rendering cost dominates the hosting budget.
Whatever the application ships. Pre-rendering moves the HTML cost, not the JavaScript cost.
The bundle has downloaded and hydrated — exactly as with SSR. The early paint is deceptive.
- — Content that is the same for everyone: documentation, marketing, changelogs, help centres.
- — Traffic spikes, since serving a file from an edge cache costs nothing per visitor.
- — Pages that must survive the origin being down, because nothing at request time depends on it.
- — Cases where build-time freshness is genuinely good enough, and someone has said so explicitly.
- — Personalised or permission-dependent views, which cannot be built once for everybody.
- — Data that changes faster than the build can run, where the page is confidently wrong rather than late.
- — Very large page counts, where a full rebuild becomes the deployment bottleneck.
- — Teams who read early paint as speed and stop, leaving the interactivity gap unexamined.
The same application code, delivered in a way that overlaps with content rather than queueing behind it.
Region by region, as each one streams and hydrates. There is no single moment, which is exactly why a single number misrepresents it.
- — Pages where one slow data source would otherwise delay everything else on the screen.
- — Layouts with a clear priority order, where the header, navigation and primary content can be sent first.
- — High-latency networks, where getting the browser working on something early matters more than total bytes.
- — Applications that want SSR's indexable content without SSR's all-or-nothing first byte.
- — Pages that need a definitive HTTP status or headers computed from data — those must be decided before the stream starts.
- — Regions whose space is not reserved, since arriving content then moves what a person is already reading.
- — Infrastructure that buffers responses, which silently converts streaming back into ordinary SSR.
- — Teams without a way to measure per-region arrival, who cannot tell whether the streaming is working.
Only the code the interactive regions need. Content that is content stays content.
Each island becomes interactive when its own small bundle arrives — often before a monolithic bundle would have finished downloading.
- — Content-heavy pages with a few interactive parts: articles with a search box, docs with a version switcher, storefronts with a cart widget.
- — Low-end devices, where the saving is parse and execute time rather than bytes.
- — Teams who can draw a real boundary between content and interaction and keep it drawn.
- — Progressive enhancement, since the page is fully functional as HTML before any island loads.
- — Applications that are interactive nearly everywhere — a spreadsheet is not a page with islands, it is one island.
- — Shared state across many islands, which reintroduces the coordination the architecture was avoiding, over a harder boundary.
- — Frameworks and component libraries that assume a single client-side tree and a single root.
- — Designs where "interactive" keeps expanding until every region is an island and the bundle is whole again.
There is no winner here on purpose. A marketing page and a spreadsheet-shaped internal tool have almost nothing in common, and the strategy that is obviously correct for one is obviously wrong for the other. The transferable skill is being able to say which milestone your product is actually judged on — and what you are giving up to move it.