Rendering patterns — or why the barfi sits on the counter and the jalebi is fried while you wait
Every sweet shop runs two kitchens at once. The trays of barfi were made at six in the morning — you point, you pay, you're out in forty seconds. The jalebi is fried in front of you and you wait four minutes for it. Neither is the better system; they're answers to different questions. Every rendering strategy with a three-letter name is a version of that same decision: when does this page get made? Here are the five real answers, what each one costs, and how to tell which of your pages is barfi and which is jalebi.
The issue
Walk into any decent sweet shop and you'll find two completely different kitchens operating in the same room. On the left, trays of barfi and laddoo made at six in the morning, sitting under glass. You point, they weigh, you pay, you're out in forty seconds. On the right, a man frying jalebi to order into a kadhai of hot syrup. You wait four minutes and you get something the first counter physically cannot give you.
Neither counter is the better idea. They're answers to different questions, and the shop runs both because some things keep and some things don't. Every rendering pattern with an acronym — SSG, SSR, ISR, PPR — is a version of exactly this decision, and it comes down to one question you can ask about any page on the internet: when does this page get made?
There are only three possible answers. Before anybody asked for it. At the moment somebody asks. Or after it has already arrived on their phone. Everything else in this issue is a refinement of one of those three.
Made in the morning: static
The page is built once, when you deploy, and turned into an actual file. That file gets copied to servers all over the world, and when someone in Chennai opens it they get it from a machine in Chennai. Nothing runs. Nothing is decided. It's a tray under glass.
Nothing beats this when it fits, and it's worth being clear about why. The page arrives in roughly the time it takes light to get there and back. There is no server to fall over when you get on the news, and no server bill that grows with traffic. It keeps working when your database is down, because it never needed the database. The site you're reading this on is built this way — every essay is a file, and the whole thing costs nothing to serve.
The catch is that the page is whatever it was at build time. Change a price at 3pm and the page keeps saying the old price until somebody rebuilds. And that rebuild is not free: a shop with 40,000 product pages, each needing a data fetch, has a build measured in tens of minutes — which means fixing a typo also takes tens of minutes.
Fried to order: server rendering
At the other end, the page is built fresh for every single visit. This isn't a performance choice, it's a necessity choice: you cannot pre-bake somebody's feed, their cart, their account page or their order history, because those pages are about a specific person and that person hadn't logged in when you deployed.
The price is that every visit now runs your code on a server, and usually talks to a database. Time-to-first-byte goes from something like 40ms to 300ms and up — and unlike the static case, that cost multiplies by your traffic. A million views is a million function invocations and a million database round-trips, which is a real line item and a real thing that falls over on the day you least want it to.
Made in the browser: client fetch
The third option: send a static page immediately, and have it fetch its own data once it lands. You've seen this a thousand times — the layout appears instantly, and then every card on it is a grey shimmering rectangle for a second before the real content drops in.
It's genuinely good for some things: the data is always current, and the shell arrives fast. But two costs are worth naming. The first is that the thing the user came for is the last thing to arrive — a fast-feeling empty page is still an empty page. The second is layout shift: if the skeleton isn't exactly the size of the real content, everything jumps when the data lands. That's the maddening experience where you go to tap a link and something loads above it and you tap the wrong thing instead.
The one most real sites should be using: ISR
Now the interesting one, because it's what most content-heavy sites genuinely want and most of them don't know it exists. Go back to the bakery: instead of baking once at 6am, they put a fresh tray out every hour. Customers still get counter speed — they never wait for an oven — and the food is never more than an hour old.
Incremental Static Regeneration is that. Each page is a static file with a timer on it. When the timer expires, the page is marked stale — but here's the part that's hard to picture and worth slowing down for: the visitor who triggers the rebuild is not the one who waits for it. They're handed the old page instantly, the rebuild happens in the background, and the next visitor gets the fresh one. Nobody ever waits for the oven.
This is what makes a 40,000-page catalogue tractable. You can't rebuild all of them every time a price moves, and you can't afford to render all of them per visit. So each page rebuilds at most once a minute, and — the quiet part — only the pages people actually visit ever rebuild at all. The long tail nobody opens costs you nothing.
And then the better version: don't rebuild on a timer, rebuild when the thing actually changes. Your CMS fires a webhook the moment someone hits publish, and that one URL regenerates in a couple of seconds. A newsroom publishing a correction shouldn't have to choose between waiting out a 60-second timer and rebuilding forty thousand pages; it should mean one page updating, immediately, and nothing else moving.
Two things that get mentioned together and shouldn't be
Edge rendering is about distance and nothing else. If your server is in Virginia and your reader is in Mumbai, a round trip is roughly 250 milliseconds of pure geography before a single line of your code runs. You cannot optimise your way out of the speed of light — you can only move closer. Edge rendering puts small copies of your server in dozens of cities so the cooking happens near the customer.
Streaming is about order. Instead of holding the whole tray until the slowest dish is ready, the waiter brings the rice as soon as it's rice. The page's header, navigation and article body go out immediately; the one slow personalised block — the recommendations that need a database — streams in when it's ready. The reader starts reading during the wait instead of after it.
Put those two together and you get the newest shape, which frameworks call partial prerendering: a static shell served instantly from a CDN, with a hole in it that streams in per-visitor. It's the same carving argument Issue 026 makes about JavaScript, applied to server work — refusing to let one small personalised box set the price for the entire page.
Picking one, without a two-week argument
The framework is two questions, in order, per page. Not per site — per page, and the fact that modern tools let you mix strategies within one codebase is the single most underused thing about them.
As a rough map: a portfolio or blog is static with no JavaScript at all. Docs, news and marketing are static or ISR with a few interactive islands. A storefront is static plus ISR, with the cart as the one live piece. A social feed or a personal dashboard is rendered per request. And a design tool is a client-side app that happens to be delivered over HTTP.
If you don't write the code
This is the most expensive decision in this whole series, and almost none of the cost is visible in the feature. The same page, the same traffic, can differ by fifty times in infrastructure bill depending on which of these five it uses. A file served from a CDN at a million views a month costs roughly nothing; the same page rendered per request is a million invocations and a million database queries, and you will feel every one of them.
It's also the answer to "why did the site go down the day we got written up?" A static page does not care that a hundred thousand people arrived at once — it's a file, and CDNs serve files for a living. A per-request page cares enormously, and the failure arrives at precisely the moment the attention does.
One metric worth knowing by name, because it settles arguments: TTFB, time to first byte — how long before anything at all arrives. If your TTFB is 800 milliseconds, no amount of frontend work will save you, because at 800ms nothing has started yet. That number is almost entirely a rendering-strategy number, and it's the first thing to look at before anyone starts optimising images. Issue 019 is the one about measuring before you change things.
How each one goes wrong
The honest summary is the sweet shop one. Ask what keeps and what doesn't. Most of your site keeps — put it on the counter, and stop paying a chef to make it again for every customer who walks in.
For the framework-specific detail — the Next.js APIs behind each of these and the full comparison tables — patterns.dev's Rendering Patterns writeup is the right next stop, and web.dev on Core Web Vitals is where the metrics in this issue are defined properly.