"There are three HTTPs in active use today. They all speak the same vocabulary. They just package the envelope differently."
The Family Tree
HTTP has evolved without breaking its application-layer contract. The methods, status codes, headers, and URIs you learn in this quest work identically across every version. What changes is the wire encoding: how those four parts of the message are laid down on the network.
- HTTP/0.9 (1991) — one-line GET only. Historical curiosity; long dead.
- HTTP/1.0 (1996) — introduced status codes, headers, methods beyond GET. Still no Keep-Alive, so a new TCP connection per request.
- HTTP/1.1 (1997, refined through 2022's RFC 9112) — persistent connections by default, chunked transfer encoding, mandatory
Hostheader, pipelining (rarely used). Text-based on the wire — what you'd type into netcat. - HTTP/2 (2015, RFC 9113) — binary framing, multiplexing (many concurrent streams over one TCP connection), header compression (HPACK), prioritization. Same semantics, much faster delivery.
- HTTP/3 (2022, RFC 9114) — runs over QUIC (UDP-based) instead of TCP. Faster handshake (TLS bundled in), no head-of-line blocking, connection migration. Same semantics again.
What Each Version Solved
HTTP/1.1's killer feature was Keep-Alive: keep the TCP connection open so the next request reuses it. Combined with the mandatory Host header, this enabled virtual hosting (multiple sites on one IP) and made web pages dramatically faster.
HTTP/2's killer feature was multiplexing: many requests interleaved as frames on one TCP connection. Before HTTP/2, browsers opened ~6 parallel TCP connections per origin to fetch assets in parallel. With HTTP/2, one connection handles everything. Header compression (HPACK) cut repeat-request overhead — every request to the same origin used to re-send all those User-Agent, Cookie, Accept-* headers as raw text; HTTP/2 deduplicates them.
HTTP/3's killer feature was killing TCP's head-of-line blocking. In HTTP/2, multiplexed streams share one TCP connection, so a single lost packet stalls every stream. QUIC (HTTP/3's transport) handles loss per-stream, so other streams keep flowing. Also: faster handshake and connection migration (your phone can switch networks mid-request).
When You Need to Care About the Version
For most application code, the answer is never. Your HTTP client (httpx, fetch, axios, curl) and the server negotiate the version transparently. You write the same code for HTTP/1.1 and HTTP/3.
You start caring when:
- Mobile networks — HTTP/3 wins on lossy connections (HTTP/2's head-of-line blocking hurts there).
- Many small assets — HTTP/2/3's multiplexing beats HTTP/1.1's per-origin connection cap.
- Long-lived streaming — HTTP/2 frames let you mix SSE streams with regular requests on one connection.
- Firewalls / corporate networks — UDP (and therefore HTTP/3) is sometimes blocked; you need HTTP/2 fallback.
- Debugging — HTTP/2's binary wire is not human-readable.
curl --http1.1gives you a text trace; HTTP/2 needs Wireshark or browser DevTools to decode.