← Writing

Page speed: the three things that actually matter

Run any site through a speed tool and you get a wall of recommendations: minify this, defer that, eliminate the other. Most of those items are worth single-digit milliseconds. Fixing all of them will not make a slow site fast.

Three things decide it. Everything else is rounding. Here they are in the order the browser encounters them, which is also the order you should fix them in.

1. How long the server takes to say anything

Before the browser can render a single pixel it has to receive the first byte of HTML. If your server thinks for 900 milliseconds before it starts talking, the visitor has already spent almost a second looking at a blank page, and nothing you do downstream gets that back.

This is where most genuinely slow small-business sites lose their time, and it's invisible to the usual advice because it happens before the page exists. A CMS on shared hosting running thirty plugins, each doing uncached database queries on every request, will spend most of a second assembling a page that hasn't changed in six months.

The bar: under 200 milliseconds to first byte for a page that isn't personalized. The way to hit it is almost never a bigger server. It's to stop rebuilding a static page on every visit — a full-page cache, or better, generating the HTML ahead of time and letting the web server hand over a file.

2. What stands between the HTML and the first paint

Now the HTML is arriving, and the browser starts parsing. Two things in your <head> can stop it cold.

Synchronous scripts. A plain <script src="..."> in the head halts HTML parsing until that file is fetched and executed. Five of them from four different vendors, and you've serialized five network round trips before any content is drawn. Almost every one of them belongs at the end of the body, or marked defer.

Every extra origin. This is the one people underestimate. Each new hostname you pull from — a font host, a tag manager, a chat widget, an analytics vendor — costs a DNS lookup, a TCP handshake, and a TLS handshake before it delivers its first byte. On a mobile connection with 100 ms of latency, that's roughly a third of a second per vendor, spent before the vendor has done anything useful. Four third-party origins in the head is over a second of pure setup.

Fonts do it too. A web font blocks text from painting until it arrives unless you tell it not to; font-display: swap plus self-hosting the file removes an origin and a render block in one move.

3. How much JavaScript the phone has to execute

Bytes are the part everyone measures, and bytes are the smaller half. A 400 KB JavaScript bundle downloads in about a second on decent mobile data — then has to be parsed, compiled, and run, and that cost is paid by the phone's CPU. A mid-range Android from a few years ago does that work several times slower than the laptop you tested on.

This is what makes a page unresponsive rather than merely slow: taps that don't register, a menu that opens half a second late, a form that stutters while typing. It's measured by Interaction to Next Paint, which replaced First Input Delay as a Core Web Vital in March 2024, and the threshold is 200 ms at the 75th percentile. (The other two you care about: Largest Contentful Paint under 2.5 seconds, layout shift under 0.1.)

The uncomfortable version: if your brochure site ships a full frontend framework to render text that never changes, you are spending your visitor's battery to redraw content that could have been in the HTML.

The reason your test looks fine

Here's the trap in the whole exercise. You run the audit on a desktop, on office fiber, and get an 89. Your customer is on a three-year-old phone on rural LTE and the same page takes nine seconds.

That gap isn't uniform. Image weight scales with bandwidth; JavaScript cost scales with CPU. Test on a fast machine with a fat pipe and the JavaScript problem all but disappears from the measurement while the image problem stays visible. You optimize what you can see, ship it, and the real numbers barely move.

Test throttled, on a simulated mid-tier phone, or on an actual cheap Android. The ranking of your problems changes completely. And check field data if you have it — what real visitors experienced beats any lab run on your desk.

The part that isn't a fix

All three of these are architectural. Server response time is decided by how the page is generated. Render blocking is decided by what you agreed to embed. JavaScript weight is decided by the framework choice made on day one.

Which is why "we'll optimize it later" mostly doesn't happen. Later, the 300 KB of JavaScript turns out to be the site, the third-party scripts belong to somebody else, and the only real fix is a rebuild. Sites are fast by construction or slow forever, with a plateau of small wins in between. Build the plain version first, and add weight only when something earns it.

If your site is slow and you want to know which of the three it is, we host sites built the other way around.


Need this kind of thinking applied to your own setup? Get in touch →