Frontend Labs
⋯

Chapter 30 — HTTP/2 and HTTP/3

In one sentence

HTTP/2 sends many requests at once over a single TCP connection, and HTTP/3 moves to a new transport over UDP to fix the one problem HTTP/2 couldn't.

The problem HTTP/2 solved

HTTP/1.1 can only handle one request at a time per connection. A modern web page needs 50–100 resources. So browsers opened ~6 connections per site and queued everything — each connection paying its own TCP + TLS handshake, and each request waiting for the one before it ("head-of-line blocking" at the HTTP layer).

What HTTP/2 does

   HTTP/1.1                            HTTP/2
   6 connections, one request           ONE connection, many
   at a time each                       requests interleaved

   conn1: [req A......][req D...]       conn: [A][B][C][A][B][D][C][A]...
   conn2: [req B........]                     \_______________________/
   conn3: [req C.....]                         all mixed together,
   ...                                         reassembled at the other end

Key features:

  • Multiplexing — many requests in flight on one connection, interleaved.
  • Header compression (HPACK) — repeated headers (cookies, user-agent) cost ~1 byte instead of hundreds.
  • Binary framing instead of text — faster to parse, less ambiguous.
  • Stream priorities — tell the server the CSS matters more than the footer image.

Result: usually much faster, and it made "domain sharding" and sprite sheets obsolete.

The problem HTTP/2 couldn't solve

Everything is on one TCP connection. And TCP guarantees in-order delivery of the whole byte stream. So:

   If ONE packet is lost, TCP holds back EVERYTHING behind it --
   including data belonging to completely unrelated requests.

   [req A data][req B data][LOST][req C data][req D data]
                             ^
                    everything after this waits,
                    even though C and D arrived fine

This is TCP head-of-line blocking. On a clean network HTTP/2 is great. On a lossy one (mobile, congested Wi-Fi), it can be worse than HTTP/1.1's six independent connections, because with six connections a loss only stalls one of them.

What HTTP/3 does

HTTP/3 runs over QUIC, a new transport protocol built on UDP.

Wait — UDP? The unreliable one? Yes, but QUIC implements its own reliability per stream:

   QUIC streams are INDEPENDENT.
   A lost packet for stream B stalls ONLY stream B.
   Streams A, C, and D carry on.

Plus:

Feature Benefit
Encryption and transport handshake merged 1 round trip to set up (or 0 on a repeat visit) instead of TCP+TLS's 2–3
Connection ID instead of the 4-tuple Your connection survives changing networks — walk out of Wi-Fi onto mobile and the download continues
Always encrypted No unencrypted QUIC exists
Implemented in the application, not the kernel Can be improved without OS upgrades — which is why it's built on UDP

Why build it on UDP? Because middleboxes on the internet only really understand TCP and UDP. Inventing a genuinely new protocol number would have been blocked everywhere. UDP is the escape hatch that let a new transport be deployed.

Which version are you using?

Browsers negotiate automatically: TLS's ALPN picks HTTP/2, and an Alt-Svc header or DNS HTTPS record advertises HTTP/3 for next time. If UDP is blocked, it falls back.

Practice (20 min)

A. Check what a site supports:

curl -sI --http2 https://example.com | head -1        # "HTTP/2 200"
curl -sI --http1.1 https://example.com | head -1      # "HTTP/1.1 200"
curl -sI --http3 https://cloudflare.com | head -1     # needs curl built with HTTP/3

B. Look for the HTTP/3 advertisement:

curl -sI https://cloudflare.com | grep -i alt-svc
dig cloudflare.com HTTPS +short          # look for alpn="h3"

C. See QUIC traffic on your machine. You're probably already using it:

sudo tcpdump -i any -n 'udp port 443'

Browse a Google or Cloudflare-fronted site. That UDP traffic on 443 is HTTP/3.

D. Compare in your browser. DevTools → Network → right-click the column headers → enable Protocol. Reload a few sites and see h2, h3, and http/1.1 in the wild.

E. See multiplexing: in DevTools, look at the waterfall for an HTTP/2 site. Notice many requests starting at nearly the same moment, rather than in batches of six.

Common confusions

  • "HTTP/3 uses UDP so it's unreliable." QUIC adds reliability on top, per stream. It's as reliable as TCP, with better loss behaviour.
  • "Should I upgrade my site to HTTP/2?" If you use a CDN or a modern web server, you probably already have it. It's essentially free.
  • "Is HTTP/1.1 dead?" No — it's simple, universal, and fine for APIs and server-to-server calls. It's browsers loading complex pages that benefit most from H2/H3.

Check yourself

  1. What was the main limitation of HTTP/1.1 that HTTP/2 fixed?
  2. What is TCP head-of-line blocking, and why does it hurt HTTP/2 specifically?
  3. Why is QUIC built on UDP rather than being a brand-new protocol?
  4. What does "connection migration" mean and why is it useful?

Further reading

  • Book (free): High Performance Browser Networking, Chapters on HTTP/2 — hpbn.co. Still the clearest explanation.
  • Article: "HTTP/3: From root to tip" and "The Road to QUIC" — Cloudflare blog. Excellent and readable.
  • Video: "HTTP/1 vs HTTP/2 vs HTTP/3" — Hussein Nasser (he has a whole playlist on this) or ByteByteGo's animated version.
  • Spec: RFC 9114 (HTTP/3) and RFC 9000 (QUIC) — for later.

End of Part 7 — Milestone check

  • I have typed an HTTP request by hand with nc
  • I know the meaning of the 2xx/3xx/4xx/5xx families
  • I can explain why keep-alive matters
  • I can explain the three guarantees of TLS and how certificates work
  • I have inspected a real certificate with openssl
  • I can explain head-of-line blocking and how HTTP/3 avoids it

Generated from real-life-guide-v1.md · 8 Oct 2026 16:36