Vivian Voss

The Count That Was Never Justified

javascript htmx webperf architecture

Last week's piece set out the diagnosis: four things broke at the same time in the modern web stack. Today we take the first of them on its own. The count. The fact that an ordinary install brings several hundred megabytes of code, a hundred-thousand-file directory and a fifteen-hundred-package transitive closure to a project that has not yet run a line.

The standard reading of this is that the count is the cost of features. A modern application does more than the static HTML of 1998; therefore it requires more code; therefore the count is the price one pays for the experience. The argument is honest in form. It is also, on the evidence, not true.

We can take the evidence in three pieces. The numbers of the floor and the median. The kilobyte tier that already does the job. The companies and projects walking back to it, in production, at scale.

The Floor and the Median

The HTTP Archive Web Almanac measures the web every year by crawling the top several million sites and tabulating the result. Its 2025 Page Weight report has the numbers most useful here.

The median page in 2025 ships 697 kilobytes of JavaScript on its home page, 632 KB on inner pages. The 90th percentile, the heaviest tenth of the web, ships 1,979 KB of JavaScript before the first character of content arrives.

The 10th percentile, the lightest tenth of the public web (which by definition includes pages that work), ships 87 KB. That is the floor. It exists. A tenth of the sites that the rest of the web is supposedly imitating manage their work without crossing it.

The Web's JavaScript, by Percentile (2025) 10th pct 87 KB — the floor, and it works median 697 KB home • 632 KB inner 90th pct 1,979 KB — before the first character of content arrives A tenth of the web ships 87 KB every day. The floor is not theoretical. Source: HTTP Archive Web Almanac 2025, Page Weight

The floor is not theoretical. It is what a tenth of the web does, every day.

Kilobytes, Not Megabytes

The argument that interactivity costs megabytes runs into a single library and breaks.

HTMX, written by Carson Gross, is fourteen kilobytes minified, around five kilobytes gzipped. It gives a browser full reactivity over the wire. The pattern is plain: HTML attributes describe what an interaction should do; the server sends back HTML, which the browser swaps in. There is no virtual DOM. There is no bundler. There is no node_modules. The library is one file. The application can be PHP, Python, Ruby, Go, Rust, Lisp, anything that emits HTML on request.

HEY and Basecamp run on Hotwire, the Rails team's equivalent pattern: HTML over the wire, Turbo for navigation, Stimulus for the small client-side islands that actually need behaviour. The result is fully interactive, in production, used by paying customers, on a stack whose total client weight is measured in the tens of kilobytes.

HTMX is not alone. A whole tier of small hypermedia and reactivity libraries now works in the same order of magnitude: Alpine.js at around ten kilobytes, Datastar for the server-sent-events approach, the HTMX team's own fixi at barely more than a kilobyte. One of them, and I should declare it plainly, is mine. htm/a is a study I built to see how low the floor goes: server-side reactivity in about four kilobytes on the wire, a type-safe Rust core, no dependencies, with htma.run running on it. I do not support it and I am not selling it. It exists to prove to me, in production and not on a slide, that the floor is lower than the industry pretends.

Same Job, a Different Order of Magnitude standard install Next.js ~ 700 MB on disk, to a gigabyte before you write a line reactivity on the wire, in production HTMX ~ 14 KB min, 5 KB gz Alpine.js ~ 10 KB Datastar SSE-oriented, same order fixi (HTMX team) ~ 1.3 KB compressed htm/a — the author's own study ~ 4 KB on the wire • type-safe Rust core • runs htma.run Hotwire (HEY, Basecamp) — reactivity over the wire a page needs 14 KB, or 5, or 50 — not 697

Server-rendered HTML, augmented where it earns its keep, is not a regression. It is what the lightest tenth of the web already does, and it is what the Hotwire-and-HTMX cohort have demonstrated at production scale.

A modern interactive web page does not need 697 kilobytes of JavaScript. It needs 14, or 5, or 50, depending on how many islands of behaviour the page actually has. The number is in the right power of ten only when the architecture is in the right place.

The Production Walk-Backs

The strongest argument against the standard count is not the existence of alternatives. It is the firms walking back to them, in public, with their reasons attached.

Wikipedia runs on MediaWiki, written in PHP 8.3, server-rendered. Sixty million articles, two thousand requests per second sustained, no SPA at any layer. The interactivity is in the parts of the page that need it. The rest is HTML.

GOV.UK, the United Kingdom's government services portal, is mandated to progressive enhancement by its design system. HTML-first. JavaScript is added where it improves a workflow, not where it replaces one. The site serves several million users a day and is, by any reasonable measure of accessibility, more reliable than the average commercial web property.

Hacker News is rendered server-side in Arc, a Common Lisp dialect. It has been since launch in 2007. The page opens before a spinner would have time to appear.

Cloudflare replaced its standard web tier, nginx with Lua scripting, with a Rust service called Pingora, written from scratch. The result, at one trillion requests per day, was around seventy per cent less CPU usage for the same workload. This is not a startup demonstration. This is the world's largest reverse proxy, in production, replacing its own previous standard with a smaller, faster, less layered piece of code, and publishing the result.

And one historical note that should not be missed. Netflix, in 2017, measured its logged-out home page after removing client-side React. The improvement in Time to Interactive was around fifty per cent. The page is what an unauthenticated visitor sees first, and the right architecture for it was server-side rendering with a small amount of progressive enhancement.

This is not only a move for firms at that scale. I should declare an interest here too: I built a small web server of my own as a study, a Rust core with a Lua edge, and have run this site and my publisher's shop on it for months without incident. It is not a product and I do not support it for anyone else; it is a proof, to me, that the smaller stack holds in production and not only in a benchmark.

The Production Walk-Backs Wikipedia 60M articles, PHP server-rendered, no SPA GOV.UK progressive enhancement HTML-first, mandated Hacker News server-side Lisp since 2007 Cloudflare Pingora ~70% less CPU Rust, at 1 trillion req/day Netflix (2017) ~50% faster TTI removed client React htm/a + own web server Rust core, Lua edge this site + a publisher's shop If the biggest names do the work for less, the count is a choice not a price the architecture forces — the standard reading was wrong

If Cloudflare and Netflix and the UK government and Wikipedia and Basecamp have looked at the count and chosen to do the work for less, the count is a choice. It is not a price the architecture forces. The standard reading was wrong.

What Was Bought With the Count

What did the industry get in exchange for the megabytes?

Some real things. Component reuse across teams. Type safety, where TypeScript is taken seriously. A vocabulary that allows designers and developers to share a model. None of these are nothing.

And several things that are not what they were sold as. A "rich ecosystem" that is in fact a transitive closure no one can audit, which the next Wednesday will take. A "developer experience" whose dev-server takes ninety seconds to start. A "framework" whose default install ships more code than the entire operating system underneath it. A vocabulary that calls the cost a feature and the feature a cost.

The trade was not honest. The buyer was not told what they were buying.

Why the Count Persists

A reasonable question, given the alternatives in production, is why the standard stack still ships. The answer is not technical. It is two things at once.

The first is the hiring market. A junior engineer trained on React/Webpack/Babel/ESLint/Jest is a known quantity. A senior engineer asking for Hotwire is offering the company a re-hiring problem. The vocabulary that developer experience had built was the curriculum, and the curriculum became the labour market.

The second is the deployment economy. Vercel, Netlify, AWS Amplify and a handful of others have a business model that depends on the modern stack being heavy and the modern engineer being a builder rather than a maintainer. Their hosting price scales with the bundle. Their integrations require their tooling. Their tooling requires more bundle.

Neither of these is wrong from any individual actor's point of view. Each follows its own incentives. The count is what falls out when the incentives line up.

Why the Count Persists (the answer is not technical) the hiring market junior on React/Webpack/Babel = a known quantity senior asking for Hotwire = a re-hiring problem the deployment economy Vercel, Netlify and the rest need the stack heavy price scales with the bundle tooling requires more bundle the incentives line up — the count is what falls out

The Point

The count is a choice. It is not a price the architecture forces.

HTMX shows it can be done in kilobytes. MediaWiki shows it can be done at sixty million pages. Cloudflare shows it can be done at a trillion requests a day. The work to keep the count where it is requires more effort than the work to bring it down. The reason it stays is that nobody in the chain has an incentive to bring it down: not the platform, not the framework, not the bootcamp, not the agency.

The trade was made on behalf of every web team in the industry, by an ecosystem none of them had elected, and the bill is paid in attention, in electricity, in pager calls at three in the morning when a transitive dependency turns out to have been compromised in the small hours.

Next Wednesday: the boundary that was never drawn. The trade comes with a security cost the architecture cannot fix.