The part that never changes: Request and response
Every version below still speaks the same basic language: a client sends a request (a method like GET or POST, a path, and headers), and a server sends back a response (a status code like 200 or 404, headers, and a body). What's changed release to release isn't that model. It's the machinery underneath it, aimed entirely at one problem: a real page needs dozens of requests (HTML, CSS, JavaScript, images), and waiting for them one at a time is slow.
Picture a kitchen sending dishes out to several diners. With HTTP/1.1, each server delivers complete dishes in order; using several servers adds parallelism. HTTP/2 lets one server interleave portions for different diners, but a missing tray holds up all later portions at the receiving counter because TCP requires one delivery order. HTTP/3 tracks the portions for each diner separately: diners can receive their complete portions without waiting for someone else's missing portion. A dropped tray can still contain portions for several diners, and everyone still shares the kitchen's capacity.
HTTP/1.1: Parallel connections as a workaround
Within a single TCP (Transmission Control Protocol) connection, HTTP/1.1 responses have to come back in the order they were requested; a slow response blocks everything queued behind it on that same connection. Browsers worked around this by opening several TCP connections to the same server at once, commonly six, so requests could run in parallel across them. It works, but every one of those connections pays its own TCP handshake cost and, over HTTPS, its own TLS (Transport Layer Security) handshake cost too.
HTTP/2: Multiplexing many requests over one connection
HTTP/2 fixes the workaround at the application layer: many requests and responses are broken into frames and interleaved over a single TCP connection, so nothing has to wait its turn behind an unrelated response anymore, and headers are compressed (HPACK) instead of repeated in full on every request. But the connection underneath is still one ordinary TCP stream, and TCP still guarantees strictly in-order delivery. If a single packet belonging to any one stream is lost, TCP holds up every stream's data behind it until that packet is retransmitted, even though the other streams' data has nothing to do with the loss.
HTTP/3: Fixing the transport itself
HTTP/3 runs over QUIC, a transport protocol carried in UDP (User Datagram Protocol) datagrams instead of TCP. QUIC tracks reliability and ordering separately for each stream. A lost QUIC packet can contain STREAM frames from several streams, so every stream missing data from that packet may have to wait. Streams with no missing data have no transport-level ordering dependency on those streams. This does not provide independent network paths: connection-level congestion control and flow-control limits still affect progress.
QUIC integrates TLS 1.3 (there's no unencrypted HTTP/3). Eligible resumed connections can send early application data with 0-RTT, but the server can reject it and replay risks restrict its safe use. It is not a guarantee that every request or handshake takes zero round trips.
| Version | Connections used | Multiplexing | Transport | Key feature |
|---|---|---|---|---|
| HTTP/1.1 | Several parallel TCP connections | No (one response in flight per connection, effectively) | TCP | Simple, universally supported |
| HTTP/2 | One TCP connection | Yes, multiplexed streams | TCP | Header compression (HPACK), fixes application-level blocking |
| HTTP/3 | One QUIC connection | Yes, independent streams | UDP (via QUIC) | Fixes transport-level blocking, built-in TLS 1.3, faster setup |
TCP's connection-wide in-order delivery causes the transport blocking left over in HTTP/2. QUIC keeps reliable, ordered delivery within each stream but removes that ordering requirement between streams. It changes where the guarantee applies, not whether reliable ordering exists at all.