HTTP has gone through four major versions. Each one fixed a bottleneck of the previous one.
In simple language: HTTP/1.0 opened a new connection per request. 1.1 reused connections. HTTP/2 sent multiple things at once on one connection. HTTP/3 ditched TCP entirely.
HTTP/1.0 (1996)
One TCP connection per request. Open, send request, get response, close.
The cost: TCP handshake every single time. Loading a page with 30 images? 30 handshakes. Painfully slow.
HTTP/1.1 (1997)
Introduced persistent connections (keep-alive) by default. The TCP socket stays open and we can reuse it for multiple requests.
It also added pipelining — sending multiple requests without waiting for responses. But responses still had to come back in order, so a slow response blocked all the ones behind it (head-of-line blocking). Most browsers never enabled pipelining because of this.
To speed things up, browsers opened 6 parallel connections per domain. Better than nothing, but wasteful.
HTTP/2 (2015)
Built on Google’s SPDY. The big idea: multiplexing. One TCP connection, many concurrent streams.
Key features:
- Binary protocol instead of text — faster to parse.
- Stream multiplexing — multiple requests/responses interleaved on a single connection.
- Header compression (HPACK) — repeated headers like
User-Agentget compressed. - Server push — server can send resources the client hasn’t asked for yet (later deprecated, rarely used well).
Problem: HTTP/2 still runs over TCP. If a single TCP packet is lost, all streams pause until it’s retransmitted. TCP-level head-of-line blocking.
HTTP/3 (2022)
Same semantics as HTTP/2 but built on QUIC instead of TCP. QUIC runs on UDP.
Why this matters:
- Each HTTP stream is an independent QUIC stream. A lost packet only stalls its own stream, not all of them.
- TLS 1.3 is baked in. The handshake is faster — often 0-RTT for repeat visits.
- Connection migration: switching from Wi-Fi to mobile data doesn’t drop the connection (uses a connection ID, not IP+port).
In simple language: HTTP/3 is HTTP/2’s idea done right, on a transport that doesn’t get in the way.
Side-by-Side Comparison
Checking Which Version We Use
# curl shows the negotiated version
curl -I --http2 https://www.cloudflare.com
curl -I --http3 https://www.cloudflare.com
# In Chrome DevTools → Network → Protocol column shows h2, h3, http/1.1
Interview Tip
The key story to tell: head-of-line blocking moved up the stack and finally got solved. 1.1 had it at the request level, 2 had it at the TCP level, 3 fixed it with QUIC. If you can explain that, you’ve nailed the evolution.