HTTP/3
ActiveHTTP/3 is the third major version of HTTP, defined by RFC 9114 (June 2022). It runs over QUIC (RFC 9000) instead of TCP. QUIC is a UDP-based transport that provides multiplexing without head-of-line blocking, 0-RTT connection establishment, and built-in TLS 1.3 encryption. HTTP/3 is now the default on Cloudflare, Fastly, and most major CDNs. Approximately one-third of all web traffic uses HTTP/3 as of 2026.
In one line
HTTP/3 (RFC 9114, June 2022) runs over QUIC (RFC 9000) instead of TCP. QUIC is UDP-based with built-in TLS 1.3, eliminating TCP handshake overhead and head-of-line blocking. Each HTTP stream is an independent QUIC stream – a lost packet on one stream does not block others. 0-RTT resumes sessions with zero round trips. Negotiated via Alt-Svc header (h3) or HTTPS DNS record. Deployed by default on Cloudflare, Fastly, Google, and Meta.
Quick Reference
| Field | Size | Description |
|---|---|---|
| Transport | QUIC over UDP | HTTP/3 uses QUIC (RFC 9000) as transport instead of TCP. QUIC runs over UDP port 443. Firewalls that block non-TCP traffic on 443 will block HTTP/3 – implementations always fall back to HTTP/2 or HTTP/1.1. |
| TLS | Built-in TLS 1.3 | QUIC integrates TLS 1.3 natively. There is no separate TLS handshake – key negotiation happens in the QUIC handshake. 1-RTT for new connections, 0-RTT for session resumption. |
| Streams | Independent QUIC streams | Each HTTP request/response pair is an independent QUIC stream. A lost UDP packet only blocks the stream it belongs to, not other streams. This eliminates HTTP/2's head-of-line blocking (which was at the TCP level). |
| 0-RTT | Session resumption | Clients that have previously connected can resume the session with 0-RTT, sending application data in the first packet. Reduces latency to zero round trips for returning users. Replay attack risk: only use 0-RTT for idempotent requests (GET, HEAD). |
| QPACK | RFC 9204 | Header compression for HTTP/3. Replaces HTTP/2's HPACK. QPACK handles dynamic header tables across QUIC streams without causing blocking. Two additional QUIC streams carry encoder/decoder instructions. |
| Alt-Svc negotiation | h3 service parameter | HTTP/2 response includes Alt-Svc: h3=":443";ma=86400 to advertise HTTP/3 availability. Browser upgrades on the next connection. HTTPS DNS records (SVCB/HTTPS) also advertise h3 for first-connection upgrade. |
| Connection migration | QUIC CID | QUIC connections are identified by Connection IDs, not IP:port tuples. Clients can migrate between networks (Wi-Fi → cellular) without reconnecting. QUIC retransmits in-flight data seamlessly after migration. |
| ALPN | h3 | Application-Layer Protocol Negotiation identifier for HTTP/3 is 'h3'. Previous QUIC drafts used h3-29, h3-Q050, etc. Always use h3 for RFC 9114 compliant HTTP/3. |
Key Characteristics
No head-of-line blocking
HTTP/2 multiplexes over a single TCP stream – one dropped TCP segment blocks all streams. HTTP/3 streams are independent QUIC streams over UDP. A dropped packet only affects that one stream.
0-RTT connection resumption
Returning clients send application data in the first QUIC packet with 0 round trips. New connections use 1-RTT (vs HTTP/2's 2-RTT: TCP + TLS). Critical for mobile users and latency-sensitive applications.
TLS 1.3 mandatory
QUIC requires TLS 1.3 – there is no way to use HTTP/3 without encryption. Older TLS versions are not supported. This eliminates legacy cipher attacks at the transport level.
UDP firewall bypass
Some enterprise firewalls, corporate proxies, and certain mobile networks block UDP traffic on port 443. HTTP/3 implementations always fall back to HTTP/2 (TCP) when QUIC is blocked. Clients detect this via Alt-Svc failure.
Message Format
# HTTP/3 is binary – no human-readable wire format
# Conceptually identical to HTTP/2 headers
# QUIC handshake (1-RTT for new connection):
# UDP packet: Initial (ClientHello embedded in QUIC CRYPTO frames)
# Server: Handshake + 1-RTT keys
# Client: Handshake complete + first HTTP request
# HTTP/3 request (HEADERS frame over QUIC stream)
# Sent as QPACK-compressed headers on stream 0:
:method = GET
:path = /api/users
:scheme = https
:authority = api.example.com
accept = application/json
# Alt-Svc upgrade: server advertises HTTP/3 in HTTP/2 response
HTTP/2 200 OK
Alt-Svc: h3=":443"; ma=86400
# Next connection from this client uses HTTP/3# Browser upgrade flow
1. Browser connects via HTTP/2 (TCP)
2. Server responds with: Alt-Svc: h3=":443"; ma=86400
3. Browser stores h3 hint for api.example.com:443 4. Next request: browser tries QUIC on UDP:443 5. If QUIC succeeds: all further requests use HTTP/3
6. If QUIC blocked by firewall: browser falls back to HTTP/2
# HTTPS DNS record (SVCB) for first-connection upgrade
# api.example.com. HTTPS 1 . alpn="h3,h2"
# Browser sees h3 in DNS before first TCP connection
# Check if site uses HTTP/3
curl --http3 -I https://api.example.com
# Or check in Chrome DevTools Network tab
# Protocol column shows: h3 = HTTP/3, h2 = HTTP/2
# nginx HTTP/3 config snippet:
# listen 443 quic reuseport; # QUIC/HTTP/3
# listen 443 ssl; # TCP/HTTP/2 fallback
# add_header Alt-Svc 'h3=":443"; ma=86400';