Why static beats dynamic for 99% of sites

Most sites reach for a server, a database, and a runtime they never needed. Here is the case for shipping HTML you can cache forever — and the narrow set of cases where dynamic actually earns its keep.


The default architecture for a new website is wildly over-built. You reach for a server because the tutorial had one, a database because the framework assumed it, and a runtime that has to boot, query, render, and serialize on every single request — all to return a page that hasn’t changed in three weeks. The machinery is real, the bill is real, and the failure modes are real. The content is static.

Most of the web is documents. A blog post, a marketing page, a changelog, a docs site — these are read far more often than they’re written, and they’re identical for every visitor. When the output is the same for everyone and changes rarely, computing it fresh on every request is not flexibility. It’s waste with extra steps.

What “static” actually buys you

A static site is HTML, CSS, and a little JavaScript, generated once at build time and served from a CDN edge. The substitution sounds small and the consequences are not. You trade per-request computation for build-time computation, and that single move collapses an entire category of problems.

There’s no server to patch, no database to back up, no connection pool to exhaust, no N+1 query hiding behind a slow page. Your “infrastructure” is a bucket of files behind a cache. The attack surface shrinks to almost nothing, because there’s almost nothing to attack — no SQL to inject, no runtime to exploit, no secrets sitting in an environment waiting to leak.

Performance stops being a project. A cached file served from an edge node a few milliseconds from the user is about as fast as the web gets, and you get it by default instead of by heroics. The page that took a dynamic stack 400ms to assemble arrives in 20ms because it was assembled once, weeks ago, and has been sitting ready ever since.

The fastest request is the one your server never has to think about. Static sites win not because they’re clever, but because they refuse to do work that was already done. — the principle I keep coming back to

The economics nobody mentions

Dynamic hosting is priced like a thing that’s awake. You pay for a process that has to be ready to respond, which means you pay whether anyone shows up or not. Idle capacity is still capacity, and capacity is still a line item.

Static hosting is priced like storage and bandwidth, both of which are nearly free at the scale a normal site operates. A personal site, a company blog, a documentation portal — these run on the free tier of half a dozen providers indefinitely, and the moment they get popular, a CDN absorbs the traffic without you touching anything. The cost curve for static is flat where the cost curve for dynamic bends sharply upward exactly when you’d least want it to: under load.

// "dynamic": run on every request, forever
app.get("/post/:slug", async (req, res) => {
  const post = await db.posts.findBySlug(req.params.slug);
  const html = await render(layout, post);
  res.send(html); // identical for every visitor, computed every time
});

// "static": run once at build, serve from the edge
for (const post of await db.posts.all()) {
  const html = await render(layout, post);
  await writeFile(`dist/post/${post.slug}.html`, html);
}

The dynamic version does the same render forever. The static version does it once and walks away. Same output, wildly different bill.

When dynamic actually earns it

This isn’t an argument against servers — it’s an argument against reflexive servers. Some things genuinely have to be computed per request, and pretending otherwise is its own kind of waste.

If the page is different for every user — a logged-in dashboard, a personalized feed, a cart — you need dynamic rendering, full stop. If the data is changing by the second and staleness is unacceptable — live prices, live scores, live availability — a cache won’t save you. And if the core of the product is the computation — a search engine, an editor, a simulator — then the server isn’t incidental, it’s the point.

The honest test is simple: does this page change based on who is asking or when they ask? If the answer is no, it should be a file. The mistake isn’t using dynamic rendering. The mistake is using it for the 99% of pages that are just documents wearing a server costume.

Common questions

When should a site be static instead of dynamic?

Use static when the page looks the same for everyone and changes rarely: blogs, docs, marketing pages, changelogs. The test is whether the output depends on who is asking or when. If it does not, it should be a prebuilt file served from a CDN.

When do you actually need a dynamic server?

Three cases earn a server. Pages that differ per user, like dashboards, carts, and personalized feeds. Data that changes by the second where staleness is unacceptable, like live prices, scores, and availability. And products where the computation itself is the point, like search, editors, and simulators.

Why is static hosting cheaper than dynamic hosting?

Dynamic hosting bills for a process that stays awake to answer requests, so you pay whether traffic shows up or not. Static hosting bills for storage and bandwidth, which are nearly free at normal scale, and a CDN absorbs traffic spikes without extra work.

Is static slower to update when content changes?

There is a build step, but it runs once per change rather than once per request. For content that updates a few times a day or week, that trade is worth the speed, cost, and security you get back.