How HTTP Evolved: From 1.1 to HTTP/3 and QUIC

•5 min read•

HTTP is the language browsers and servers use to talk. It has been through four major versions, and each one was a response to a specific bottleneck that the previous version had run into. Following that chain is one of the clearest ways to understand why the modern web performs the way it does, because the problems being solved are still the problems you hit when a page loads slowly.

HTTP/0.9 and 1.0: one request, one connection

The first version, from 1991, was almost comically simple[1]. HTTP/0.9 had a single method, GET, no headers, and no status codes. You asked for a document and got the document. That was the entire protocol.

HTTP/1.0, documented in 1996[2], added the pieces that made the web usable: headers, status codes, and support for content types beyond plain HTML, so images and other media could travel too. It still had a serious limitation. Each request opened a fresh TCP connection and closed it when the response finished. A page with ten images meant ten separate connections, each paying the cost of a full TCP handshake before any data moved.

HTTP/1.1: keep the connection open

HTTP/1.1 arrived in 1997[3] and became the backbone of the web for nearly two decades. Its headline change was persistent connections[4]. Instead of opening and closing a connection for every file, the browser could keep one open and send several requests over it, which removed a huge amount of handshake overhead.

It also added other now-standard features: the Host header, which let many sites share one IP address[5], chunked transfer encoding for streaming responses, and better caching controls.

But 1.1 had a flaw that shaped everything after it: head-of-line blocking. On a single connection, requests are answered in order. If the first response is slow, everything queued behind it waits, even if those later responses are ready. Browsers worked around this by opening several connections to the same server at once, usually around six, and by bundling files together to reduce the number of requests. Those workarounds kept the web moving, but they were workarounds, not fixes.

HTTP/2: many requests, one connection

HTTP/2, standardized in 2015[6] and based on Google's earlier SPDY experiment, attacked head-of-line blocking directly. Its central idea is multiplexing. A single connection carries many independent streams at once, and responses can come back interleaved and in any order, so a slow response no longer blocks the ones behind it.

To make that work, HTTP/2 changed the wire format from text to a compact binary framing. It added header compression, called HPACK[7], because requests repeat the same headers over and over and sending them in full every time wastes bandwidth. It also introduced server push, a feature meant to let servers send resources before the browser asked, though push proved awkward in practice and has largely fallen out of use.

GET /style.css HTTP/2
GET /app.js   HTTP/2
GET /logo.png HTTP/2

Those three requests now travel over one connection, in parallel, instead of fighting for a queue. The result was a real speedup, and the old tricks of sharding files across many domains became unnecessary and sometimes harmful.

The limit HTTP/2 could not cross

HTTP/2 solved head-of-line blocking at the HTTP layer, but it still ran on top of TCP, and TCP has its own version of the same problem one level down. TCP guarantees that bytes arrive in order. If a single packet is lost, TCP holds back everything that came after it until the missing piece is retransmitted, even if those later bytes belong to completely different streams.

So on a shaky network, one lost packet could stall every stream on an HTTP/2 connection at once. The protocol had moved the bottleneck, but not removed it, because the bottleneck now lived in the transport layer underneath.

HTTP/3 and QUIC: changing the foundation

The fix required replacing TCP, which is where QUIC comes in. QUIC is a transport protocol built on top of UDP, and HTTP/3, standardized in 2022, runs on it[8]. UDP does not enforce ordering, which sounds like a downside until you realize it is exactly what lets QUIC manage each stream independently.

In QUIC, a lost packet only stalls the one stream it belonged to[9]. The other streams keep flowing. That removes transport-level head-of-line blocking entirely, which is the thing HTTP/2 could not do.

QUIC also folds the connection setup and the TLS encryption handshake together[10], so establishing a secure connection takes fewer round trips, sometimes just one, and sometimes zero when resuming an earlier session. And because a QUIC connection is identified by a connection ID[11] rather than the usual IP-and-port pair, it can survive a network change. Walking from wifi to cellular no longer drops the connection and forces a reconnect.

What this means in practice

Most of this is invisible. You do not choose a version, your browser and the server negotiate the best one they both support, and major sites and content delivery networks already serve HTTP/2 and HTTP/3. The practical takeaways are smaller than the history suggests.

On HTTP/2 and HTTP/3, the old performance habits from the 1.1 era can actually hurt. Bundling everything into one giant file and spreading assets across many domains were ways to beat 1.1's limits, and on a multiplexed connection they get in the way of fine-grained caching and parallel delivery. The modern approach is to ship reasonably sized resources and let the protocol carry them efficiently.

The larger lesson is in the shape of the story. Each version removed a bottleneck and exposed the next one down. HTTP/1.1 removed per-request connections and revealed head-of-line blocking. HTTP/2 removed it at the HTTP layer and revealed it in TCP. HTTP/3 replaced the transport itself. The web you use today is fast because people kept chasing that bottleneck down through every layer until they ran out of layers to fix.

Sources (11)
  1. Wikipedia: Hypertext Transfer Protocol
  2. RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0
  3. RFC 2068: Hypertext Transfer Protocol -- HTTP/1.1
  4. Wikipedia: HTTP persistent connection
  5. Wikipedia: Virtual hosting
  6. RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2)
  7. RFC 7541: HPACK: Header Compression for HTTP/2
  8. RFC 9114: HTTP/3
  9. Wikipedia: QUIC
  10. RFC 9001: Using TLS to Secure QUIC
  11. RFC 9000: QUIC: A UDP-Based Multiplexed and Secure Transport