Networking
HTTP/3
HTTP over QUIC over UDP — eliminates TCP head-of-line blocking, enables 0-RTT resumption
HTTP/3 is the third major version of HTTP, standardized as RFC 9114 in June 2022. Unlike HTTP/2 (which uses TCP), HTTP/3 runs on QUIC (RFC 9000) — a UDP-based transport with built-in TLS 1.3 encryption, multiplexed streams without TCP head-of-line blocking, connection migration across networks (Wi-Fi → cellular without re-handshake), and 0-RTT session resumption. Initially deployed by Google in 2013, standardized through 2022. Supported by 75%+ of major browsers and CDNs (Cloudflare, Akamai, Fastly) by 2024. Performance gains: 5-15% lower mobile-network page load times, due especially to elimination of TCP HOL.
- StandardizedRFC 9114 (June 2022)
- TransportQUIC over UDP
- TLS1.3 always-on
- 0-RTT resumptionyes
- Connection migrationyes
- Browser support75%+ by 2024
Interactive visualization
Press play, or step through manually. The visualization is yours to drive — try it before reading on.
Watch the 60-second explainer
A condensed visual walkthrough — narrated, captioned, under a minute.
Why HTTP/3 matters
- Mobile networks. Cellular and mobile Wi-Fi typically see 1-5% packet loss; HTTP/3's per-stream reliability avoids HTTP/2's stalls. Page-load p75 drops 5-15% on mobile.
- Real-time apps. WebRTC-style use cases (video calls, gaming) benefit from QUIC's faster handshake and migration; lost packets don't cascade.
- CDN optimization. Cloudflare, Akamai, Fastly serve ~30% of their HTTP traffic over HTTP/3 by 2024, with 0-RTT cutting TTFB on returning visitors by 100-200ms.
- Packet-loss-prone networks. Long-distance international links (200ms+ RTT, 2-3% loss) gain dramatically — HOL blocking would otherwise serialize loss-recoveries.
- Connection migration. Phones switching Wi-Fi to LTE keep their session — important for video streaming, long uploads, and chat apps.
- Defense against ossification. TCP can't evolve because middleboxes inspect/block unfamiliar TCP options. QUIC's full encryption (including transport headers) ends middlebox interference.
- Always TLS. No plaintext mode; every connection is TLS 1.3 encrypted by spec. Auditing and compliance benefit.
The protocol stack
HTTP/3 lives at the top of a four-layer stack:
- Application: HTTP/3 (RFC 9114) — request/response semantics, header compression via QPACK.
- Transport+Crypto: QUIC (RFC 9000) — streams, congestion control, loss recovery, encryption.
- Network: UDP — unordered, unreliable datagrams.
- Link: IP + Ethernet/Wi-Fi/cellular.
Compare HTTP/2's stack: HTTP/2 → TLS 1.2/1.3 → TCP → IP. HTTP/3 collapses the TLS+TCP layers into QUIC, where encryption and reliability are co-designed.
QUIC carries multiple streams within one connection. Each stream is a logically independent ordered byte stream, identified by a 62-bit ID. HTTP/3 maps one HTTP request/response pair to one stream. Connection-level state (flow control, congestion window) is shared; stream-level state (sequence numbers, reassembly buffer) is independent.
Head-of-line blocking explained
HTTP/2 multiplexes N requests over one TCP connection. The TCP layer guarantees in-order byte delivery to the application. If packet 1000 (carrying part of stream A) is lost, TCP buffers packets 1001-1010 until the retransmission of 1000 arrives — even if 1001-1010 carry data for streams B, C, D. The application sees nothing on B, C, D until A's loss is repaired.
On a 1% packet loss link, this serializes recoveries. With 6 in-flight streams and one stream losing a packet, all 6 stall for one RTT. Real-world impact: HTTP/2 multiplexing helps less than expected on lossy networks.
QUIC's solution: per-stream sequence numbers and reassembly. The QUIC layer reassembles each stream independently. A lost packet on stream A blocks only A; streams B, C, D continue delivering data to the application. QUIC papers (Langley et al., SIGCOMM 2017) measured 3-5% improvement in average page load and 15%+ on the long tail of mobile networks.
The QUIC handshake
QUIC fuses transport setup and TLS into one handshake.
1-RTT (first connection):
- Client → Server: Initial packet with TLS ClientHello, transport parameters, connection ID.
- Server → Client: Initial + Handshake packets with ServerHello, certificate, transport parameters.
- Client → Server: Handshake completion + first request (encrypted with derived keys).
Application data flows in the second flight = 1 RTT. Compare HTTP/2 over TCP+TLS 1.3: 3-way TCP handshake (1 RTT) + TLS 1.3 (1 RTT) = 2 RTTs minimum. QUIC saves a full RTT.
0-RTT (resumed connection):
- From a previous connection, client cached a session ticket and a PSK (pre-shared key).
- Client → Server: Initial packet with ClientHello + 0-RTT-encrypted application data (e.g., GET request).
- Server processes the request immediately, sends response.
0-RTT means the very first packet from the client carries application data. Cloudflare reports 0-RTT cuts TTFB by 100-200ms for repeat visitors.
Caveat: 0-RTT data is vulnerable to replay attacks. An attacker can capture and re-send a 0-RTT packet. So only idempotent requests (GET) should use 0-RTT; POST/PUT must use 1-RTT.
Connection migration
TCP connections are tied to the 5-tuple (src IP, src port, dst IP, dst port, protocol). Change any of those and the connection breaks. When a phone hands off from Wi-Fi (192.168.1.x) to cellular (10.x.x.x), all TCP connections die — fresh handshakes required.
QUIC connections are identified by an opaque Connection ID, decoupled from IP/port. The handshake establishes one or more Connection IDs. When the client's IP changes:
- Client sends a packet from the new IP with the existing Connection ID.
- Server receives the packet, verifies the Connection ID, and replies with a path-validation challenge.
- Client responds with the challenge token, proving ownership of the new path.
- Server starts using the new IP for subsequent packets.
Total cost: ~1 RTT, no full handshake. In-flight requests don't fail. Especially valuable for: mobile video streaming (Netflix, YouTube), VoIP and video calls, large uploads from laptops moving between networks, IoT devices on roaming connections.
QPACK header compression
HTTP/3 can't use HPACK (HTTP/2's header compressor) because HPACK assumes ordered, reliable byte stream — exactly what QUIC's per-stream model breaks. QPACK is a redesign for QUIC's stream model.
QPACK splits compression state into a static table (predefined common headers), a dynamic table (recently-seen headers), and per-stream encoded references. Encoder and decoder run on dedicated streams; updates to the dynamic table are sent on those streams while header blocks reference table indices.
The trade-off: HPACK's tighter coupling to ordering gives slightly better compression ratios; QPACK's looser coupling avoids HOL blocking. In practice, QPACK achieves within ~5% of HPACK's compression efficiency.
Deployment status (2024)
- Browsers: Chrome 87+ (Nov 2020), Firefox 88+ (Apr 2021), Safari 14+ (Sep 2020), Edge — all stable. Combined market share >95%.
- CDNs: Cloudflare ~28% of traffic on H3, Akamai 30%+, Fastly 25%+, Google CDN universal.
- Servers: Nginx (since 1.25, May 2023), HAProxy (2.6+), Caddy (built-in), litespeed, Microsoft IIS (Server 2022).
- Libraries: quiche (Cloudflare, Rust/C), msquic (Microsoft), aioquic (Python), node:quic (experimental), Go quic-go.
- Mobile: Android 11+ has built-in QUIC for Chrome and apps using Cronet. iOS Safari supports it but limited fallback config.
Adoption isn't yet universal because corporate firewalls often block UDP except DNS, and some mobile carriers throttle UDP. The standard practice is "Alt-Svc" — serve over HTTP/2 first, advertise HTTP/3 availability, let the browser try UDP and fall back if blocked.
Alt-Svc and protocol negotiation
HTTP/3 is opportunistic — there's no DNS or URL marker. The flow:
- Browser opens HTTP/2 over TCP+TLS to example.com.
- First response includes header:
Alt-Svc: h3=":443"; ma=86400(advertise HTTP/3 on UDP 443, valid for 86,400s = 24h). - Browser caches this advertisement.
- Next request: browser races UDP (HTTP/3) and TCP (HTTP/2). UDP wins if reachable.
- If UDP fails (timeout, ICMP unreachable), browser invalidates the Alt-Svc cache and falls back to HTTP/2.
This is intentionally opportunistic — no broken page if UDP is blocked. Modern Chrome implements "Happy Eyeballs"-style racing for HTTP/3 vs HTTP/2 to minimize first-paint delay.
Performance and CPU cost
Real-world numbers from public benchmarks (Cloudflare 2023, Google 2022):
- Mobile (3G/4G with 1-2% loss): 5-15% faster page load vs HTTP/2.
- Fast Wi-Fi (low loss, low RTT): Roughly even with HTTP/2; sometimes 0-2% slower.
- International long-haul (200ms RTT, 2-3% loss): 20-30% faster on the long tail.
- 0-RTT TTFB: 100-200ms savings on returning visitors.
- Server CPU: ~2x of HTTP/2 for equivalent throughput (user-space crypto, no TSO/LRO, no offload yet).
- Memory: ~30% higher per connection (reassembly buffers per stream, larger control state).
Hardware acceleration is starting to land (Cloudflare's QUIC offload announcement 2024, Microsoft's NIC partnerships). When mature, QUIC CPU should approach TCP+TLS within 10-20%.
Common misconceptions
- "HTTP/3 is always faster." Gains are workload-specific. On low-latency low-loss links, HTTP/3 ties or marginally loses to HTTP/2 because UDP processing has more user-space overhead.
- "HTTP/3 uses TCP underneath." Pure UDP. There is no TCP in the HTTP/3 stack.
- "TLS is optional in HTTP/3." Built into QUIC; mandatory by spec. There's no plaintext HTTP/3.
- "You need a new server." Most existing TLS terminators (Nginx, HAProxy, Caddy) added QUIC support 2022-2023; same configuration model.
- "HTTP/3 deprecates HTTP/2." No — both will coexist for years. HTTP/2 over TCP works through firewalls that block UDP and uses less server CPU.
- "QUIC packets are like TCP segments." QUIC packets contain frames (multiple types: stream data, ACK, control). Multiple frames from different streams can share one packet.
- "Connection IDs leak privacy." Designed to rotate — clients receive new connection IDs from the server and switch periodically to avoid linkability across paths.
Frequently asked questions
Why does HTTP/3 use UDP instead of TCP?
Three reasons. (1) TCP is implemented in the OS kernel — changes require kernel updates that take a decade to roll out globally. UDP is a thin user-space layer; QUIC ships in the browser and the server binary. (2) TCP guarantees in-order byte stream delivery, which causes head-of-line blocking when one packet is lost. QUIC implements per-stream reliability so a lost packet only blocks its stream. (3) UDP allows the transport to coevolve with TLS — QUIC's handshake combines transport setup and crypto in 1-RTT (or 0-RTT), versus TCP+TLS 1.3's 2-RTT minimum.
What is TCP head-of-line blocking and how does QUIC solve it?
HTTP/2 multiplexes many requests onto one TCP connection. If a single packet (carrying any of the streams) is lost, TCP holds back ALL streams until retransmission arrives — TCP guarantees byte-level in-order delivery and can't selectively skip ahead. On a 5% packet-loss link, this nullifies HTTP/2's multiplexing benefit. QUIC implements per-stream reliability: each stream has its own sequence numbers and reassembly buffer. A lost packet on stream 3 blocks only stream 3; streams 5, 7, 9 continue delivering. Real-world gains: 5-15% page-load improvement on mobile networks with 1-2% packet loss.
What is 0-RTT and how does it differ from 1-RTT?
First-time connection: client sends ClientHello + transport params, server replies ServerHello + handshake. Application data flows in the second flight = 1-RTT. Resumed connection (returning client): the client encrypts application data with a session ticket from the previous connection and sends it in the very first packet alongside the handshake. Server processes immediately = 0-RTT. Catches: 0-RTT data is replayable (an attacker can capture and replay it), so only idempotent requests (GETs) should use 0-RTT in practice. Cloudflare and Google enable 0-RTT for static asset fetches; POST/PUT use 1-RTT.
How does connection migration work?
TCP connections are 5-tuple (src IP, src port, dst IP, dst port, protocol). When a phone switches from Wi-Fi to cellular, src IP changes — TCP connection breaks, requiring a fresh handshake. QUIC connections are identified by a Connection ID (an opaque 64-bit value), not the 5-tuple. The client picks a new IP, sends a packet with the same Connection ID; the server validates ownership via path-validation challenge and resumes. No re-handshake needed; in-flight requests don't fail. Important for video streaming (Netflix, YouTube) and long-running uploads where mid-session network switches are common.
What about middleboxes that block UDP?
Some corporate firewalls block UDP except DNS (port 53) and a few others. About 3-7% of users globally hit UDP blocks (varies by region). HTTP/3 servers always negotiate via Alt-Svc header from an HTTP/2 connection — the first request is over TCP, response includes 'Alt-Svc: h3=:443; ma=86400' indicating HTTP/3 availability. The browser tries UDP on the next request; if it fails (no response in ~300ms), the browser falls back to HTTP/2 and remembers the failure. Cloudflare reports ~28% of their requests use HTTP/3 at the edge as of 2024.
Why isn't HTTP/3 universally faster?
On low-latency, low-loss links (datacenters, fiber-to-the-home, fast Wi-Fi), HTTP/3 is roughly even with HTTP/2 — sometimes slightly slower because UDP processing in user space has more overhead than kernel-optimized TCP. The wins are real on lossy mobile networks (3-5% packet loss), high-RTT international links, and reconnection-heavy workloads. CPU cost is also higher: QUIC servers spend ~2x CPU vs TCP for the same throughput due to user-space crypto and lack of segmentation offload (kernel TSO/LRO). Hardware QUIC offload is starting to arrive (Cloudflare 2024, Microsoft) but isn't universal.