Static HTML vs Svelte: which is actually faster?
This question comes up constantly. Someone picks Svelte for a project, someone else says "just use static HTML," and then everyone argues about benchmarks that don't reflect real conditions. I got tired of the debate without data, so here's an honest look at what the numbers actually mean — and when each answer is correct.
What we're actually measuring
When people say "faster," they mean different things. Let's be precise about what actually matters for a user:
- FCP (First Contentful Paint) — when the user sees something
- LCP (Largest Contentful Paint) — when the main content is visible
- TTI (Time to Interactive) — when the page responds to clicks
- TBT (Total Blocking Time) — how long the main thread is jammed
- CLS (Cumulative Layout Shift) — does the page jump around
Google uses these as ranking signals. They're also what your users actually experience. Let's go through each.
The static HTML baseline
A well-written static HTML page has essentially no competition on FCP and LCP. The browser receives HTML, parses it, paints it. No JavaScript runtime to boot. No hydration step. No virtual DOM diffing. The critical rendering path is as short as it can physically be.
This site — raphaelreck.com — is static HTML. PageSpeed Desktop: LCP 1.6s. That's not because I'm a genius; it's because there's nothing in the way between the HTML and the screen.
The catch: static HTML has no state. No reactivity. No components. The moment you need a dropdown that remembers its position, a form that validates live, or a UI that updates without a page reload — you start reaching for JavaScript. And once you're writing vanilla JS to manage DOM state by hand, the complexity cost grows faster than you'd expect.
What Svelte actually does differently
Svelte is a compiler, not a runtime framework. This is the key distinction that gets lost in framework wars. React ships a runtime — the React library itself runs in the browser and manages the virtual DOM. Svelte compiles your components into plain JavaScript at build time. The output is essentially optimized vanilla JS with no library overhead.
<!-- Svelte source -->
<script>
let count = 0;
</script>
<button on:click={() => count++}>
Clicked {count} times
</button>
What that compiles to is roughly 400 bytes of vanilla JS that directly manipulates the DOM — no virtual DOM, no diffing, no reconciliation loop. The runtime cost is near zero because there is no runtime.
The actual numbers
Same content, same server (o2switch, shared hosting, France), same network conditions, measured with Lighthouse:
| Metric | Static HTML | Svelte (compiled) | React (CRA) |
|---|---|---|---|
| FCP (desktop) | 0.4s | 0.5s | 1.1s |
| LCP (desktop) | 0.6s | 0.7s | 1.4s |
| TTI (desktop) | 0.4s | 0.6s | 2.1s |
| JS bundle size | 0 KB | ~8 KB | ~140 KB |
| FCP (mobile, 4G) | 1.2s | 1.5s | 3.8s |
| Can manage state? | No | Yes | Yes |
A few things jump out. Static HTML is faster than Svelte — but only by about 100ms on a desktop. That gap is real but small. The gap between Svelte and React is large and scales badly on mobile.
Where static HTML breaks down
I maintain my personal site in static HTML. It's fast, it's portable, and it has zero dependencies. But I've hit the wall twice in the past year:
First wall: the contact form. A contact form that validates live, shows inline errors, and doesn't reload the page is straightforward in Svelte and painful in vanilla JS. Not impossible — painful. You end up writing the same state management code that Svelte generates for you, except yours is messier and harder to maintain.
Second wall: the component repetition. My blog index page lists posts. Each post card has the same structure. In static HTML, I'm copy-pasting markup. One change to the card design means editing every instance. With Svelte (or Astro, which I'd actually recommend for static sites that need components), it's one component updated once.
The honest verdict
Use static HTML when:
The page is genuinely static — landing pages, blog posts, documentation, portfolios. No live UI state. You want maximum performance with zero tooling overhead. You can live with copy-pasting markup or using server-side includes.
Use Svelte when:
You need UI interactivity — forms with live validation, components with state, dashboards, anything that reacts to user input. You want near-static performance without writing DOM manipulation by hand. You're comfortable with a build step.
Use Astro when:
You want static HTML output but you also want the component model for maintainability. Astro ships zero JavaScript by default and lets you drop in Svelte (or React, or Vue) components only where you actually need interactivity. It's the best of both for content-heavy sites that have a few interactive bits.
What this means for AI readability
There's a side note worth making here. I've been thinking about this from an AI crawling perspective too — since I've been building LLMR, a format for making sites efficiently readable by AI systems.
Static HTML is significantly easier for AI systems to parse than JavaScript-rendered pages. The HTML exists in the raw source; an AI crawler gets the content in one fetch without needing to execute JavaScript. Svelte's compiled output is better than React on this front — the HTML is present in the page source after build — but it still adds JS overhead that a static page avoids entirely.
If you're building a site you want AI agents to read efficiently (and you should be thinking about this), static HTML or Astro with static output is the right choice. React or Angular SPAs are the worst case — the crawler gets an empty <div id="root"></div> and has to execute JavaScript to see anything.
More on that in the LLMR benchmark post.
Raphaël Reck is an IT Systems & Software Consultant based in Sophia Antipolis, France. 20+ years in the field, currently focused on systems architecture, legacy modernisation, and AI tooling. More at raphaelreck.com.