A Static Site Is the Fastest Website You'll Ever Build

Contents
I migrated this very site off a WordPress-style stack years ago, and the thing that finally pushed me over the edge wasn’t a security incident or a hosting bill, it was watching a page load waterfall for a simple blog post: a PHP process spinning up, a database query joining three tables to fetch a post that hadn’t changed in months, a template engine assembling HTML from fragments, and finally, after all of that, the same eleven paragraphs of text I could have served as a plain file in a fraction of the time. Every one of those steps existed to solve a problem I didn’t have — my content wasn’t changing per request, per user, or per anything. It was the same HTML for everyone, every time, and I was paying a database query’s worth of latency to reassemble it fresh on every single visit.
A static site generator solves this by moving all of that work to build time instead of request time. You write content in Markdown, run a build command, and out comes a folder of plain HTML, CSS and JavaScript files — no template engine running per request, no database to query, no application server to keep patched. The web server’s job shrinks down to the one thing web servers have always been extremely good at: handing a file to whoever asks for it. That’s the entire performance story in one sentence, and it’s worth sitting with because most “make your website faster” advice is really just working around the cost of not doing this.
Why this is actually faster, not just simpler
The obvious objection is that plenty of dynamic sites are fast too, with caching layers, CDNs and optimised queries closing most of the gap. That’s true, and it’s also an admission: a well-tuned dynamic site is fast because it’s been engineered to behave like a static site for the requests that matter, serving cached HTML instead of regenerating it. A static site gets that property for free, by construction, without a caching layer to configure, invalidate, or get wrong.
The latency difference is concrete. Serving a pre-built HTML file is essentially a filesystem read plus a network write — single-digit milliseconds on modern hardware, often served straight from the web server’s own memory cache. Rendering the same page dynamically means, at minimum, a process handling the request, a database connection (possibly a new one), one or more queries, and template interpolation, before you’re even at the point a static site started from. Under normal traffic that difference might be a few hundred milliseconds you don’t notice. Under a traffic spike — a link on the front page of a large forum, a post going unexpectedly viral — that difference is the entire story of whether your site stays up or falls over, because a static file server barely notices ten times the normal traffic while a database-backed one can fall over at three times.
What you give up, honestly
Static isn’t free of trade-offs, and pretending otherwise is how people end up disappointed after migrating.
- Anything genuinely per-user has to move to the client or to an API. Comments, live search, personalised recommendations — none of that can live in a pre-rendered HTML file, so it has to become a JavaScript call to a small separate service, which reintroduces exactly the dynamic-backend complexity you were trying to escape, just scoped down to the one feature that actually needs it.
- Build times grow with content volume. A site with a few hundred pages builds in seconds. A site with tens of thousands can start taking minutes, and if your workflow depends on previewing every edit, that lag becomes the new bottleneck you’re optimising around.
- Editorial workflows lose the “edit live” convenience. There’s no admin panel where a non-technical editor clicks save and the change is instantly visible; content lives in files, typically in Git, which is a feature for version history and a friction point for anyone who isn’t comfortable with a text editor and a commit.
How the build actually works
Here’s roughly what happens when Hugo (or Jekyll, Eleventy, Zola — the shape is the same across generators) builds this site, because understanding the pipeline explains where the speed actually comes from.
| |
Every Markdown file gets parsed, its front matter extracted, run through a templating layer that wraps it in the site’s shared layout, and written out as a finished HTML file — all before a single visitor ever asks for the page. Six seconds to rebuild over a thousand pages is the entire “server-side” cost of the site, paid once at deploy time instead of once per request, forever. The web server that ends up serving this to the public doesn’t run Hugo, doesn’t know Hugo exists, and doesn’t need a runtime capable of executing it — it just needs to serve files, which is the one job every web server since the 1990s has been optimised to do extremely well.
What “fast” actually measures
It’s worth being precise about which kind of fast a static site delivers, because the term gets used loosely enough to hide what’s actually improving. Time to first byte drops dramatically, because there’s no server-side work happening between the request arriving and the response leaving — the file already exists, fully formed, on disk or at a CDN edge. Largest contentful paint improves for the same reason: the browser isn’t waiting on a database round trip before it has anything to render. What doesn’t automatically improve is anything downstream of the HTML actually arriving — a static site with a megabyte of unoptimised JavaScript bolted onto it for interactivity can still feel sluggish, because the architecture only guarantees the server isn’t the bottleneck. It says nothing about what you do to the page after that.
This is the trap teams fall into after a static migration: they measure the win on server response time, declare victory, and then quietly reintroduce the same complexity on the client side — a JavaScript framework hydrating the whole page, a client-side router intercepting every link, analytics scripts loading synchronously before the content paints. None of that is inherent to static sites; it’s a choice people make because a static architecture doesn’t stop them from making it. The sites that stay genuinely fast after migrating are the ones that treat “no server-side runtime” as a constraint worth preserving on the client too, not just a one-time win to bank and move past.
Where static sites actually come from, and why the model holds up
The pattern predates the current wave of generators by decades — the entire web in the early 1990s was static files served by NCSA httpd and Apache, and the shift toward server-side rendering happened because sites genuinely needed per-user state: shopping carts, logins, personalised feeds. That need was real, and CGI scripts, then PHP, then full application frameworks, grew to meet it. What’s changed since then is how much of the average website’s content turns out not to need any of that. A blog post, a product page, a documentation article, a portfolio — these are the same for every visitor, and the industry spent twenty years running them through infrastructure built for a genuinely different problem, mostly because “one platform for everything” was operationally simpler for teams to reason about than maintaining two.
Static site generators are, in effect, a rediscovery that most content doesn’t need what the platform was built to provide. Hugo specifically leans into this by doing the templating work in Go at build time rather than in an interpreted language at request time, which is most of why its build times stay low even on sites with thousands of pages — the templating engine itself is compiled, not interpreted per request, and that distinction shows up directly in the build timing above.
The part people underestimate: attack surface
The performance story gets most of the attention, but the security story matters just as much and gets less airtime. A dynamic site has an application server, a templating engine, and usually a database, each with its own version, its own CVEs, and its own patch cadence to keep on top of. A static site has none of that in its public-facing path — there’s no application code running against untrusted input at request time, because there’s no application code running at request time at all. The build tool only ever runs against content you wrote yourself, on a machine that isn’t exposed to the internet, which removes an entire category of vulnerability (SQL injection, template injection, unpatched CMS plugins) by eliminating the attack surface those vulnerabilities need to exist at all.
Troubleshooting a slow or broken static build
Static sites fail in different ways to dynamic ones, and the fixes are usually simpler once you know where to look.
Build times climbing unexpectedly. Check image processing first — most static site generators re-process images (resizing, format conversion) on every build unless the results are cached, and a content folder with a few hundred unoptimised photos can turn a two-second build into a two-minute one. Enabling the generator’s build cache, or pre-processing images outside the pipeline, usually fixes this immediately.
A page shows old content after deploy. This is almost always a CDN or browser caching issue, not a build issue, since the static file on disk is correct by definition once the build succeeds. Check cache-control headers and CDN edge TTLs before assuming the generator did something wrong.
Local build works, deployed site is broken. Nearly always a base URL mismatch — static generators bake absolute paths into the output at build time, so a site built with the wrong base URL configuration will produce broken links and assets even though nothing else changed. Confirm the environment variable or config value the CI pipeline uses matches production exactly.
Search doesn’t work at all. Static sites don’t have a database to run a search query against, so search has to be either a client-side index (Pagefind, Lunr) built alongside the HTML, or an external hosted search service. If search silently stopped working after a migration, check whether the index build step is still wired into the deploy pipeline — it’s a separate step from the page build and easy to forget.
Is it worth it
For content that’s the same for every visitor — which is most of what a blog, documentation site, or marketing page actually is — yes, unambiguously. You give up live editing convenience and per-request personalisation, and in exchange you get a site that’s faster than almost anything you could tune a dynamic backend into being, with a public attack surface reduced to “serve this file,” and a hosting bill that can often drop to nearly nothing because a CDN handling static files is the cheapest kind of traffic there is to serve at scale. If your content genuinely needs to be different for every visitor on every request, static isn’t the right shape and you shouldn’t force it. For everything else, it’s worth noticing how much complexity in modern web hosting exists purely to compensate for not doing this, and how much further a generator like Hugo can go before you actually hit that ceiling.




