tech, developers, and the code underneath

issue 134· review·

HTTP/3 and QUIC, five years in

It shipped, it works, most of the web uses it, and almost nobody understands what changed. A practical review.

HTTP/3 is now the majority protocol for a large fraction of web traffic, supported by every major browser and CDN. Most developers have never thought about it, which is the correct outcome for a transport protocol.

It is still worth understanding what it actually changed, because a few of the consequences affect how you build.

the problem it solved#

HTTP/2 introduced multiplexing: many logical streams over one TCP connection. That fixed head-of-line blocking at the HTTP layer.

It did not fix it at the TCP layer. TCP delivers bytes in order. If one packet is lost, everything behind it waits, including data for streams that were completely unaffected. On a lossy connection — mobile, congested wifi — HTTP/2 could be worse than HTTP/1.1 with six connections, because one loss stalled everything instead of one sixth of everything.

QUIC moves the transport to UDP and implements reliability, ordering, and congestion control per stream. A lost packet stalls only the stream it belonged to.

what else came with it#

Encryption is mandatory and integrated. TLS 1.3 is part of the protocol rather than a layer on top. The handshake is one round trip, or zero for a resumed connection.

Connection migration. A QUIC connection is identified by a connection ID, not by the four-tuple of IP addresses and ports. Change networks — wifi to cellular — and the connection survives. Your download does not restart.

This is the feature users notice without knowing why. Walking out of a building while a video plays used to stall it.

Better loss recovery. QUIC distinguishes between packet loss and reordering more accurately than TCP, and its acknowledgment format carries more information. Recovery is faster.

Evolvability. TCP is implemented in kernels and middleboxes and cannot change, because the internet is full of devices that will drop anything unfamiliar. QUIC is in userspace and encrypted, so its internals are invisible to middleboxes and can actually be updated.

That last point is arguably the most important long-term consequence. Transport protocol ossification was a genuine crisis and QUIC is the escape hatch.

the practical consequences for you#

Domain sharding is now actively harmful. Splitting assets across static1.example.com and static2.example.com was a workaround for HTTP/1.1's connection limit. Under HTTP/2 it was pointless. Under HTTP/3 it is worse than pointless, because each domain requires a separate connection with a separate handshake and separate congestion state.

One origin. If you still have sharding from a 2014 optimization guide, remove it.

Concatenating and spriting are counterproductive. Same reasoning. Many small files multiplex fine and cache better individually.

Priority matters and is under-configured. HTTP/3 has an extensible priority scheme. Most servers use defaults. If you have a page where certain resources are critical, priority hints (fetchpriority) are worth setting and are widely supported.

UDP blocking is real but small. Some corporate networks block UDP/443. Clients fall back to HTTP/2 automatically, so this is a performance issue rather than a correctness one. Do not build anything that requires HTTP/3.

Your observability may not see it. A lot of network monitoring tooling was built for TCP. Check whether your tools actually understand QUIC or are silently reporting nothing.

the parts that were harder than expected#

CPU cost. QUIC's userspace implementation and per-packet encryption use more CPU than kernel TCP. This has improved substantially with offload support and better implementations, and it is a real cost at high volume.

Middlebox hostility. Some networks throttle or block UDP because it looks like something they should throttle. This is improving as QUIC becomes normal traffic.

Debugging is harder. You cannot read a QUIC connection with tcpdump the way you could read HTTP/1.1. qlog and browser devtools help. The tooling is younger.

the assessment#

For a user on a good connection, HTTP/3 is roughly a wash. For a user on a bad connection — mobile, congested, high latency, lossy — it is a substantial improvement, and those users are a large fraction of the world.

That is exactly the right kind of improvement: invisible to the people who were already fine, meaningful to the people who were not.

Enable it, remove your HTTP/1.1-era workarounds, and go back to not thinking about the transport layer.

get README in your inbox

One dispatch, no noise. Tech and developer news, plus the occasional long piece on the craft.

subscribe →