Latency, not bandwidth
Doubling someone’s bandwidth barely changes how fast a page feels. Halving their latency changes everything — because a page load is not one big transfer, it is dozens of small ones, each waiting for the one before it.
Before a single byte of your HTML arrives: DNS, then the TCP handshake, then the TLS handshake. Over HTTP/2 that is three round trips; QUIC (HTTP/3) folds transport and encryption together and needs two, and zero on a repeat visit. At a 50 ms round trip that is 150 ms of nothing happening, per origin.
The request chain is what to look at
Use preconnect for two or three origins at most — each one is a real connection with a real cost. Better still, self-host and have no second origin at all.
<link rel="preconnect" href="https://cdn.example" crossorigin> <!-- DNS + TCP + TLS, now -->
<link rel="dns-prefetch" href="https://cdn.example"> <!-- cheaper, DNS only -->
<link rel="preload" href="/f/inter.woff2" as="font" crossorigin> <!-- skip a level of the chain -->
What the protocol gives you
Under HTTP/2 and /3, splitting a bundle into thirty files is no longer a disaster — but it is not free either, because each file is still a compression context and a cache entry.
| HTTP/1.1 | HTTP/2 | HTTP/3 (QUIC) | |
|---|---|---|---|
| Requests per connection | 6 at a time, in order | many, multiplexed | many, multiplexed |
| A lost packet | blocks that connection | blocks every stream on it | blocks only its own stream |
| Round trips to first byte | 3 | 3 | 2, or 0 resuming |
| Still bundle everything? | yes | less so | less so |
Compression and caching
Never compress images or video with gzip or brotli — they are already compressed, and you pay CPU for nothing. And check for redirects: each one is a full round trip, and a chain of three before the real page is not rare.
| Header / choice | Effect |
|---|---|
content-encoding: br | Brotli — typically 15–20 % smaller than gzip on text; use it for HTML, CSS, JS, SVG, JSON |
cache-control: max-age=31536000, immutable | For hashed filenames. The browser never revalidates — the fastest request is the one not made |
cache-control: no-cache | For the HTML itself: cached, but always revalidated |
stale-while-revalidate=86400 | Serve the old copy instantly, refresh in the background |
| A CDN | Moves the round trips from the other side of the world to the other side of town |
103 Early Hints | Start fetching CSS while the server is still building the HTML |
The model in the lab
The simulation charges a fixed number of round trips for connection setup, one extra round trip for each dependency step, and divides bytes by bandwidth. That is a simplification — real networks have congestion control, warm connections and packet loss — but the shape it gets right is the one that matters: serial steps hurt more than size.