Skip to main content
HTTP

HTTP/2 vs HTTP/3: what changed for your API and what did not

HTTP/2 multiplexes streams over TCP; HTTP/3 uses QUIC over UDP to avoid TCP-level head-of-line blocking. Your HTTP semantics stay the same, but connection behavior changes.

Thien Nguyen
By Thien Nguyen
Updated July 21, 2026 · 3 min read

HTTP/3's headline change isn't visible in any request trace you'll read — it's that streams now ride QUIC over UDP instead of TCP, which is what finally removes transport-level head-of-line blocking. HTTP/2 already multiplexes many streams over one connection, but because that connection is TCP, a single lost packet stalls every stream until the retransmit arrives — TCP guarantees in-order bytes, so it holds everything behind the gap. HTTP/3 maps each stream onto QUIC independently, so loss on one stream doesn't block the others. Your methods, headers, and status codes are identical across both.

PropertyHTTP/2HTTP/3
TransportTCP + TLSQUIC over UDP
Stream multiplexingYesYes
Transport head-of-line blockingYesAvoided across streams
Connection migrationLimitedBuilt into QUIC

Where the difference actually shows up

The gain is real only on lossy links. On a clean wired connection with near-zero loss, HTTP/2 and HTTP/3 look nearly identical in a waterfall. Put the same page on a mobile network dropping ~1% of packets and the transport difference becomes the whole story:

MomentHTTP/2 over TCPHTTP/3 over QUIC
Packet for asset #7 is lostTCP holds all later bytes; streams 1–30 waitOnly stream #7 waits; 1–6 and 8–30 keep delivering
Retransmit lands ~1 RTT laterAll 30 streams resume togetherStream #7 resumes; others already finished
User-visible effectOne drop stalls the whole pageOne drop delays a single asset

The takeaway: HTTP/3 doesn't make a healthy network faster — it stops an unhealthy one from converting a single lost packet into a whole-page stall. That's why the wins concentrate on mobile, transit, and long-haul international routes.

Common mistakes

  • Flipping HTTP/3 on at the app while the CDN or load balancer still terminates at HTTP/2. The client negotiates with whatever answers first, so the app-level setting does nothing. HTTP/3 has to be enabled at the edge that faces the client.
  • Assuming UDP is always reachable. Some corporate and captive networks block or throttle UDP, so clients must be able to fall back to HTTP/2 or HTTP/1.1 — which every browser does automatically, but only if you haven't broken the fallback path.
  • Forgetting the Alt-Svc header. Browsers reach your origin over HTTP/2 first and only switch to h3 after they see an Alt-Svc: h3=... advertisement. No header, no upgrade — they stay on h2 indefinitely.
  • Treating the protocol as a latency fix. It can't shrink a 4 MB JSON body or speed up a slow database query. If those dominate your response time, the transport change is noise.

HTTP/2 already removed application-level request serialization for independent streams. HTTP/3 mainly removes the TCP-level loss coupling underneath them — a different layer, a different bottleneck, and neither one touches your backend latency.

Protocol upgrades are worthwhile performance work, but they aren't permission to stop measuring. Fix payload sizes and backend latency first, then enable HTTP/3 at the edge where it's a low-risk addition — and confirm the win on a genuinely lossy connection, because that's the only place the number moves.

Cover photo by Brett Sayles on Pexels.

References

Primary documentation and specifications checked when this article was last updated.

HTTPNetworkingAPIs

Related articles

All articles