HTTP/2 & HTTP/3
Learn HTTP/2 and HTTP/3 framing, multiplexing, HPACK, QPACK, QUIC loss recovery, 0-RTT safety, negotiation, fallback, rollout, and observability.
What are HTTP/2 and HTTP/3?
HTTP/2 and HTTP/3 are different wire expressions of the same HTTP semantics. Requests still have methods, target URIs, fields, content, status codes, caching rules, and authorization boundaries. What changes is how one connection frames, compresses, orders, protects, and transports those messages.
HTTP/2 multiplexes binary-framed request streams over one TCP connection and compresses field sections with HPACK. HTTP/3 maps HTTP onto QUIC over UDP, uses TLS 1.3 as part of QUIC, and compresses field sections with QPACK. QUIC can recover lost data per stream and can validate a new network path when a client address changes.
The core invariant is an HTTP version changes delivery mechanics, not business meaning. A POST is not idempotent because it crossed QUIC, a cache entry is not fresh because it arrived over HTTP/2, and a retry still needs an application-safe contract.
Meaning
HTTP semantics
Methods, status codes, fields, content, caching, authentication, and origin authority remain the application contract.
Framing
HTTP expression
HTTP/1.1 uses textual message framing, HTTP/2 uses binary frames and HPACK, and HTTP/3 uses QUIC streams plus QPACK.
Delivery
Transport behavior
TCP gives HTTP/2 one ordered byte stream. QUIC gives HTTP/3 multiple ordered streams inside one encrypted, congestion-controlled connection.
Compare the connection models before choosing a version
Connection pool
HTTP/1.1
One connection normally has one active response at a time. Clients use several TCP connections for concurrency, repeating fields as text and paying separate connection and congestion-control costs.
Multiplexed over TCP
HTTP/2
Frames from many streams interleave on one connection. HPACK removes repeated field bytes, but every stream still shares TCP's ordered delivery and congestion control.
Multiplexed over QUIC
HTTP/3
Each request uses a QUIC stream. Loss recovery is stream-aware, QPACK handles out-of-order delivery, and TLS 1.3 protection is integrated into the transport.
These versions can coexist for one origin. A browser might use HTTP/3 to an edge, while that edge uses HTTP/2 or HTTP/1.1 to an upstream. Record the protocol on every hop instead of assuming the browser's negotiated version describes the entire request path.
Follow one HTTP/2 message through frames and streams
HTTP/2 divides messages into typed binary frames. A request or response belongs to one stream, while the connection carries frames from many streams:
1 Identity
Open a stream
The initiating peer assigns a stream identifier. The stream has an explicit lifecycle from idle through open or half-closed to closed.
2 HEADERS
Send the field section
Pseudo-fields such as
:method,:scheme,:authority, and:pathcarry request control data. HPACK indexes repeated fields within the connection.3 DATA
Interleave content
DATA frames from other streams can appear between this stream's frames, so one slow application response does not monopolize the connection.
4 END_STREAM
Close independently
Each direction closes separately. A stream error can reset one exchange, while a connection error affects every stream on that connection.
Bound concurrency and flow control
SETTINGS_MAX_CONCURRENT_STREAMSlimits how many peer-initiated streams may be open. New work waits or uses another connection when the peer's limit is reached.- HTTP/2 applies flow control to DATA at both the stream and connection level.
WINDOW_UPDATEgrants more credit after the receiver consumes buffered bytes. - Flow control is not a request scheduler and does not replace application backpressure. Oversized windows can increase memory; undersized windows can idle a fast path.
- Field-list, frame-size, connection-age, request-count, and idle limits protect the server from one long-lived connection consuming unbounded state.
TCP still owns delivery order
HTTP/2 streams are logically independent, but TCP exposes one ordered byte stream. If a TCP segment is missing, later bytes cannot be delivered to the HTTP/2 parser until that gap is repaired. Frames for unrelated streams can therefore wait behind one transport loss even when their bytes reached the receiver.
Trace multiplexing under packet loss
Loading protocol, workload, concurrency, and recovery assumptions.
The lab's RTT-sized recovery pause is intentionally illustrative. Real completion time also depends on congestion control, packetization, retransmission timing, response sizes, server scheduling, connection reuse, and the shape of the loss.
Compress fields without hiding dependency risk
Ordered connection
HPACK in HTTP/2
The encoder and decoder share static and dynamic tables. Because HTTP/2 receives the connection's bytes in order, dynamic-table updates and field sections share TCP's delivery order.
Out-of-order streams
QPACK in HTTP/3
QPACK separates encoder and decoder instructions onto unidirectional streams. Static references never depend on dynamic state; dynamic references can block a field section until the needed insert arrives.
QPACK reduces the field-compression head-of-line problem that HPACK would create over independently delivered QUIC streams; it does not promise that decoding can never block. Bound dynamic-table capacity, accepted field sizes, and SETTINGS_QPACK_BLOCKED_STREAMS. Treat decompression failures and control-stream loss as connection-level operational signals.
Retire two outdated HTTP/2 assumptions
Do not design around the original priority tree
RFC 9113 deprecated HTTP/2's original dependency-and-weight priority scheme. RFC 9218 defines an extensible replacement with:
- An end-to-end
Priorityfield and hop-by-hopPRIORITY_UPDATEframes - An urgency value from
0through7, where a smaller number means higher precedence - An
incrementalflag for responses that provide useful output as chunks arrive - Explicit settings for endpoints that ignore the RFC 7540 priority signals
Priority is a scheduling hint, not proof that a server, intermediary, or CDN applied a particular order. Test the actual stack and monitor critical-resource completion.
Treat server push as an optional legacy capability
RFC 9113 still specifies HTTP/2 server push, and a client can disable it. It is not a reliable browser performance strategy: Chromium disabled HTTP/2 push by default starting with Chrome 106, and current NGINX documentation marks its push directives obsolete. Optimize cacheability and request discovery instead of requiring push for correctness or acceptable latency.
Understand what QUIC changes for HTTP/3
QUIC provides reliable streams over UDP and integrates TLS 1.3. HTTP/3 then maps HTTP control data, request streams, and push streams onto QUIC. The main consequences are:
- Independent request-stream loss recovery: missing bytes on one request stream do not prevent delivery of bytes on unrelated request streams.
- Connection-wide pressure still exists: congestion control, anti-amplification limits, connection flow control, and path capacity affect the whole connection.
- TLS is not optional: QUIC uses TLS 1.3 or a compatible newer version; the HTTP/3 ALPN identifier is
h3. - Control streams matter: each peer has one HTTP control stream, and QPACK uses dedicated encoder and decoder streams. Closing a critical stream is a connection error.
- Connection IDs support migration: a client can change IP address or port without naming a new HTTP origin. The peer validates the new path, and the load balancer must route packets for active connection IDs to the right QUIC endpoint.
Migration is not guaranteed continuity. A server can disable active migration, a new path can fail validation, NAT state can expire, and an implementation can still need a new connection. Test Wi-Fi-to-cellular transitions and edge reloads with real clients.
Negotiate HTTP/3 and preserve fallback
For HTTPS, HTTP/2 is selected with the h2 ALPN identifier during TLS over TCP. HTTP/3 uses h3 during the TLS handshake carried by QUIC. A client first needs a way to discover that the origin has an equivalent HTTP/3 endpoint.
1 Baseline path
Reach the origin
An unprimed client can establish HTTP/1.1 or HTTP/2 over TCP. ALPN chooses the version supported by both peers.
2 Advertisement
Discover HTTP/3
The origin can send
Alt-Svc: h3=":443"or publish an HTTPS DNS record understood by the client. A cached advertisement can affect later connections.3 UDP + h3
Attempt QUIC
The client opens QUIC to the advertised authority, validates the certificate and origin, and negotiates
h3.4 Compatibility
Race or fall back
If UDP, the edge, or the QUIC handshake fails, the client needs a working HTTP/2 or HTTP/1.1 path over TCP.
Build an HTTP/3 path with a tested fallback
Loading discovery, network, request, early-data, and rollout contracts.
Restrict 0-RTT to operations that tolerate replay
On a resumed QUIC connection, an eligible client can send early application data before the new handshake is confirmed. That removes waiting from the request path, but TLS early data does not have the same replay protection as normal application data. An attacker can capture and replay it.
- Default 0-RTT to off while the HTTP/3 path is being introduced.
- Classify the application operation, not only the method name. A nominal
GETthat changes state is already a broken safe-method contract. - Reject unsafe early data with
425 Too Earlyand let the client retry after handshake confirmation. - If a write must be retried, use a stable idempotency key and a durable destination record that returns the original result.
- Measure early-data offered, accepted, rejected, replay-protected, and retried requests separately from ordinary handshake success.
Roll out from an observable, reversible edge
Start where HTTP terminates. The CDN, reverse proxy, or load balancer must listen on TCP and UDP, route QUIC connection IDs correctly, present the same origin identity, and expose protocol-specific evidence.
The example uses current NGINX http2 on, listen ... quic, and h3 syntax. The current open-source NGINX documentation still labels ngx_http_v3_module experimental, so verify the deployed version, TLS library, module build, support policy, and migration behavior instead of copying a configuration blindly.
Use a controlled migration sequence
- Establish a protocol baseline for real client networks, regions, devices, routes, and connection reuse before advertising HTTP/3.
- Prove UDP reachability, certificates, ALPN, QUIC routing, address validation, connection draining, and HTTP/2 fallback at the edge.
- Advertise
h3to a small cohort with a shortAlt-Svclifetime. Keep application semantics and cache policy unchanged. - Compare error rate and user latency distributions by protocol and cohort. Track QUIC handshake failures, fallback, connection migration, retransmission, CPU, packets per second, and memory per connection.
- Expand only after the canary remains healthy across lossy and UDP-restricted networks.
- Roll back by stopping new advertisement, sending
Alt-Svc: clearwhere appropriate, preserving TCP service, and allowing or deliberately draining established QUIC connections.
Observe negotiation, not just page duration
Browser PerformanceResourceTiming.nextHopProtocol reports the negotiated ALPN identifier such as h2 or h3. It can be empty for a cross-origin resource that does not expose timing with Timing-Allow-Origin, and a proxy can change what the value represents. Treat it as one client-hop signal.
Correlate four evidence layers
- Client: protocol, route, connection reuse, navigation and resource timing, network changes, device class, and user-visible errors
- Edge: ALPN result, QUIC version, handshake outcome, fallback reason, connection age, migration, loss, congestion, stream resets, GOAWAY, and drain outcome
- Application: route, status, request duration, cancellation, retry, idempotency result, cache status, and response size
- Capacity: CPU per request and byte, packets per second, encryption cost, memory per connection and stream, UDP drops, load-balancer state, and bandwidth
Do not infer server push from transferSize === 0; cached and cross-origin timing behavior can produce values that need separate interpretation. Compare distributions, not one synthetic average, and keep the HTTP/2 control cohort during expansion.
Test the failures that protocol diagrams omit
- Block UDP while leaving TCP open; verify fallback succeeds within the product's latency and error budget.
- Drop packets on one request stream; compare unrelated-stream completion under HTTP/2 and HTTP/3 without claiming QUIC removes congestion.
- Change the client address during an active connection; verify path validation, connection-ID routing, authorization continuity, and a bounded reconnect fallback.
- Restart or drain the QUIC terminator; verify connection close, GOAWAY behavior, retry safety, and cache correctness.
- Saturate CPU and packet processing separately from bandwidth; encrypted UDP packet work can move the bottleneck even when application throughput looks unchanged.
- Reject or replay early data in a controlled environment; prove unsafe operations wait for confirmation or deduplicate durably.
- Exercise large field sections, constrained HPACK and QPACK tables, blocked QPACK streams, stream limits, slow readers, and connection-level flow-control exhaustion.
A successful migration does not mean every request uses HTTP/3. It means eligible clients gain a measured HTTP/3 path while HTTP semantics, retry safety, fallback, capacity, and rollback remain explicit.
Primary standards and operating references
- RFC 9113: HTTP/2 defines framing, streams, flow control, HPACK use, ALPN, and the deprecation of the original priority scheme.
- RFC 9114: HTTP/3 maps HTTP semantics onto QUIC and defines
h3, control streams, discovery, and HTTP/3 errors. - RFC 9000: QUIC defines streams, connection IDs, path validation, migration, flow control, and transport behavior.
- RFC 9001: Using TLS to Secure QUIC defines QUIC's TLS 1.3 integration, resumption, and 0-RTT.
- RFC 9204: QPACK defines HTTP/3 field compression and its blocked-stream controls.
- RFC 9218: Extensible HTTP Priorities defines urgency, incremental delivery, the
Priorityfield, and priority updates. - RFC 8470: Using Early Data in HTTP defines replay considerations,
Early-Data, and425 Too Early. - Chrome's HTTP/2 push removal and current NGINX HTTP/2 documentation document why push is not a current browser deployment default.
- NGINX QUIC guidance and HTTP/3 module reference document current build, listener, logging, and migration controls.
- PerformanceResourceTiming.nextHopProtocol documents client-side ALPN observation and cross-origin limitations.