Skip to content

HTTP evolution

HTTP has kept the same request/response shape — a method, a target, headers, an optional body, a status code back — since the early 1990s. What's changed underneath that shape, three times now, is how the bytes actually get from client to server. Each change was a direct response to a specific, measurable performance problem with the version before it, not a redesign for its own sake.

This short article maps out the three versions this module covers next, so the individual deep dives make sense in context rather than as three disconnected protocol names.

Why a stable request format needed a new transport three times

HTTP/1.1, standardized in 1997, was stable enough that it carried the vast majority of the web's traffic for roughly fifteen years without a successor. It didn't stay unchanged because it was flawless — it stayed unchanged because its flaws were tolerable at the scale and page complexity of the web at the time. A page with a handful of images and a stylesheet didn't suffer much from HTTP/1.1's limitations. A page with a hundred small resources, common by the early 2010s, suffered a lot: browsers were opening up to six parallel TCP connections per domain just to work around HTTP/1.1's own inability to handle multiple requests efficiently on one connection, and each of those connections still had to pay its own TCP handshake cost before a single HTTP byte moved.

HTTP/2, standardized in 2015, fixed that specific problem directly: it lets a browser send many requests over a single TCP connection at once, without one slow response blocking the others behind it — a technique called multiplexing, covered in the next article's detail.

HTTP/3, standardized in 2022, addresses a problem HTTP/2 didn't fully solve: multiplexing at the HTTP layer doesn't help if the TCP connection itself stalls on a single lost packet, since TCP guarantees strictly ordered delivery for everything on that connection regardless of which logical HTTP stream the lost data belonged to. HTTP/3 solves this by replacing TCP entirely with QUIC, a transport protocol built on UDP that can recover from loss on one stream without blocking the others.

Version Standardized Transport Core improvement over the previous version
HTTP/1.1 1997 (RFC 2068), later RFC 9112 TCP Persistent connections, chunked transfer, the Host header
HTTP/2 2015 (RFC 7540), later RFC 9113 TCP Multiplexed streams over one connection, binary framing, header compression
HTTP/3 2022 (RFC 9114) QUIC over UDP Per-stream loss recovery, faster connection setup, connection migration

Each version remains semantically compatible with the one before it — the same methods, the same status codes, the same headers in spirit. A server can serve HTTP/1.1, HTTP/2, and HTTP/3 to different clients simultaneously for the exact same content, and in production, this is normal: a client and server negotiate which version to use, and older clients simply keep getting HTTP/1.1 without anything breaking. Nothing in these three articles changes what HTTP means; all three change how efficiently it moves.

What each article actually covers

HTTP/1.1 looks at persistent connections, why pipelining — sending several requests without waiting for each response — exists in the spec but is essentially unused in practice, and the specific head-of-line blocking problem that made the six-connections-per-domain workaround necessary. HTTP/2 covers how binary framing and multiplexed streams solve that application-layer blocking, and where a subtler blocking problem still remains underneath it, at the TCP layer. HTTP/3, QUIC and UDP explains how moving to QUIC removes that remaining bottleneck, and what a UDP-based transport has to rebuild on its own to match TCP's reliability guarantees.

Sources