Skip to main content
networking

HTTP/2 and HTTP/3

11 min read
Fully authored

Multiplexing and QUIC — how HTTP got faster after 20 years.

HTTP/1.1 shipped in 1999 and ruled the web for 16 years. But by 2010, web pages had ~100 resources each (images, scripts, styles), and HTTP/1.1's one-request-per-connection model was creaking. Browsers opened 6 parallel TCP connections per host to work around it, wasting connections and confusing servers. Something had to give.

In 2009, Google engineers Mike Belshe and Roberto Peon shipped an experimental protocol called SPDY (pronounced "speedy") that multiplexed many requests over one connection. Chrome and Firefox supported it. In 2015 SPDY became HTTP/2 (RFC 7540). Then in 2018, Google shipped QUIC (Quick UDP Internet Connections), which solved TCP's head-of-line blocking. In 2022, HTTP/3 (RFC 9114) standardized HTTP over QUIC.

These aren't academic upgrades. They fundamentally change how the web performs. HTTP/2 alone typically cuts page-load time 20-30%. HTTP/3 shaves another 10-15% on top, especially on mobile networks with packet loss. As of 2024, ~35% of internet traffic runs on HTTP/3, and it's growing fast.

The specs

  • Belshe & Peon (2009) — SPDY draft at Google. Ancestor of HTTP/2.
  • RFC 7540 (2015) — HTTP/2. Binary framing, multiplexing, HPACK header compression.
  • Roskind et al. (2013) — Google's QUIC proposal. Deployed to Chrome in 2013 (called gQUIC).
  • RFC 9000 (2021) — QUIC v1 standard.
  • RFC 9114 (2022) — HTTP/3, the mapping of HTTP semantics onto QUIC.

HTTP/1.1 — the bottleneck

HTTP/1.1's core rule: one request per TCP connection at a time. If you have 100 resources to fetch, that's 100 sequential requests over 1 connection. Browsers cheated by opening 6 parallel connections — but 6 < 100. The result: head-of-line blocking at the application layer. If request #1 is slow, request #2 can't start.

HTTP/1.1 — sequential requests per connection
req: /page.html
req: /style.css
req: /app.js
req: /logo.png
req: /icon.svg
HTTP/1.1: Each request must wait for the previous to complete before it can start. Browsers open 6 parallel connections to compensate — but that's wasteful and still leaves head-of-line blocking within each connection.

HTTP/1.1 also has verbose text headers. Every request repeats: Host: example.com, User-Agent: Mozilla/5.0 …, Cookie: session=…, etc. A typical page fetches 100 resources, each with ~800 bytes of duplicated headers = ~80 KB of overhead. That's the target HTTP/2 attacks.

HTTP/2 — multiplex it all

HTTP/2 breaks the request-per-connection rule. Instead: one TCP connection carries many concurrent streams, each stream is an independent request-response pair. All streams share the connection but can complete in any order.

HTTP/2 — concurrent streams on one connection
stream 1: /page.html
stream 3: /style.css
stream 5: /app.js
stream 7: /logo.png
stream 9: /icon.svg
HTTP/2: All 5 streams flow concurrently on one TCP connection. Stream IDs are odd numbers assigned by the client. Total wall-clock: ~25% of HTTP/1.1's time.

Three big innovations enable this:

  • Binary framing: HTTP/2 is a binary protocol. Every message is a series of framed chunks tagged with a stream ID. Requests, responses, headers, and body all coexist on the wire.
  • HPACK header compression: HTTP headers are compressed with a state-machine encoding. Common headers get 1-2 bytes instead of 40-800. Cumulative bandwidth savings on typical pages: 40-70%.
  • Server push (mostly deprecated): server can proactively send resources it knows the client will need. In practice this was too hard to use safely; Chrome removed support in 2022.

HTTP/2's Achilles heel — TCP head-of-line blocking

HTTP/2 solved application-level HoL blocking (many streams per connection). But it kept TCP as the transport — and TCP itself does HoL blocking. TCP delivers bytes in order. If one packet is lost, TCP holds every subsequent packet in a kernel buffer, waiting to reassemble in order — even if those subsequent packets belong to different HTTP/2 streams.

TCP head-of-line blocking (HTTP/2)
TCP packet stream (bytes on wire):
s1
s1
s3
s3
s5
s5
s1
s3
The problem: Packet 4 (stream 3) is lost. TCP buffers packets 5-8 in kernel — refuses to deliver them to the application until packet 4 is retransmitted and arrives, because TCP guarantees in-order delivery. Streams 1 and 5 are stalled even though they have nothing to do with the dropped packet.

On a lossless network HTTP/2 is fantastic. On a lossy mobile network, HTTP/2 can be worse than HTTP/1.1 — because HTTP/1.1's parallel connections isolate each stream from the loss on the others. This is the specific problem QUIC solves.

HTTP/3 — HTTP over QUIC over UDP

HTTP/3 abandoned TCP. It runs on QUIC, a new transport protocol built on UDP that provides TCP's reliability + ordering per-stream — with independent streams that don't block each other.

QUIC streams are independent (HTTP/3)
QUIC packets — each carries frames for one stream:
s1
s1
s3
s3
s5
s5
s1
s3
The QUIC fix: Packet 4 (stream 3) is lost. QUIC tracks per-stream state — stream 3 stalls waiting for retransmit, but streams 1 and 5 continue delivering to the application immediately. No transport-level HoL blocking. The whole benefit of HTTP/2 realized on lossy networks.

Four QUIC innovations:

  • Independent streams: loss on stream 1 doesn't block stream 2. Solves TCP HoL blocking at the transport layer.
  • Integrated TLS 1.3: QUIC handshake and TLS handshake are one operation. 1-RTT from cold start to encrypted app data.
  • 0-RTT resumption: reconnecting clients can send encrypted data in the first packet, before the handshake completes.
  • Connection migration: connection ID stays stable across IP changes. Your phone switches WiFi → LTE, QUIC connection continues without dropping.

Version comparison — HTTP/1.1 vs 2 vs 3

DimensionHTTP/1.1 (1999)HTTP/2 (2015)HTTP/3 (2022)
TransportTCPTCPQUIC (UDP)
EncryptionOptional (TLS via HTTPS)Effectively required (browsers only support h2 over TLS)Mandatory + integrated in QUIC
Multiplexing❌ 1 request per connection✅ Many streams per connection✅ Many independent streams
Header formatText (verbose)Binary + HPACK compressionBinary + QPACK compression
Head-of-line blockingYes (app + TCP)TCP onlyNone
Handshake RTTs1 (TCP) + 2 (TLS 1.2) = 31 (TCP) + 1 (TLS 1.3) = 21 (or 0 with resumption)
Server pushNoneYes (deprecated 2022)None (use Early Hints)
Connection migrationNew TCP required on IP changeNew TCP + TLSSurvives via connection ID
Adoption (2024)~99% support (fallback)~99% support~35% traffic, growing
Real usersLegacy servers, old clientsEveryone (default fallback)Google, Cloudflare, Meta, YouTube, Fastly

Applied in real systems

Google (everything)
Deep dive

Google — HTTP/3 (QUIC) since 2013

Google shipped gQUIC in Chrome + Google servers in 2013 (5 years before IETF standardization). YouTube, Search, Maps, Gmail all prefer HTTP/3 when the client supports it. ~40% of Google traffic is now HTTP/3.

Read the deep dive →
Cloudflare
Deep dive

Cloudflare — HTTP/3 at every PoP

Cloudflare enabled HTTP/3 in beta in 2019, GA in 2020. Every website behind Cloudflare (millions) automatically serves HTTP/3 to compatible clients. Reader can inspect via alt-svc header.

Read the deep dive →
YouTube
Deep dive

YouTube — HTTP/3 for video streaming

YouTube moved to HTTP/3 aggressively because mobile-network packet loss was killing HTTP/2 performance. QUIC's per-stream isolation means one video chunk dropping doesn't stall the next chunk from arriving.

Read the deep dive →
Facebook / Meta
Deep dive

Facebook — HTTP/3 for Instagram and WhatsApp

Meta rolled out HTTP/3 across Instagram and WhatsApp starting 2020. Their engineering blog reports 6% lower page load time and 20% fewer request failures on mobile. Their proxygen L7 proxy speaks HTTP/3 natively.

Read the deep dive →
gRPC
Deep dive

gRPC — HTTP/2 as the wire

gRPC uses HTTP/2 as its transport. Multiplexing supports gRPC's bidirectional streaming. Long-lived HTTP/2 connections avoid re-handshake overhead. Every gRPC RPC is technically an HTTP/2 stream carrying protobuf frames.

Read the deep dive →
Nginx
Deep dive

Nginx — HTTP/2 by default

Nginx enabled HTTP/2 since 2015 (v1.9.5). HTTP/3 support landed in 1.25 (2023, experimental). Most Nginx-fronted sites you visit are already using HTTP/2.

Read the deep dive →
Apache HTTP Server
Deep dive

Apache mod_http2

Apache 2.4.17 (2015) added HTTP/2 support via mod_http2. Not as clean as Nginx's implementation — Apache's per-request thread model doesn't map perfectly to multiplexed streams, but it works.

Read the deep dive →
Browser negotiation
Deep dive

Chrome + Firefox — alt-svc discovery

Browsers learn a site supports HTTP/3 via the Alt-Svc response header. First request over HTTP/2 → server responds with Alt-Svc → browser upgrades to HTTP/3 on next request. All modern browsers speak HTTP/3.

Read the deep dive →
AWS CloudFront
Deep dive

AWS CloudFront — HTTP/3 GA in 2022

CloudFront enabled HTTP/3 for all customers by default in 2022. Turned on with a single config toggle. Most modern AWS-hosted sites now serve HTTP/3 to browsers that support it.

Read the deep dive →
LinkedIn
Deep dive

LinkedIn — HTTP/2 case study

LinkedIn migrated to HTTP/2 in 2016. Engineering blog reports: 45% reduction in the P99 page-load latency, 15% reduction in bandwidth (from HPACK). Publicly one of the best-documented HTTP/2 rollouts.

Read the deep dive →

Key takeaways

  • HTTP/1.1 → HTTP/2: single TCP connection with binary framing + multiplexed streams + HPACK header compression. Solves application-level HoL blocking.
  • HTTP/2's weakness: TCP still does HoL blocking at the transport layer. One dropped packet stalls all streams. Bad on lossy mobile networks.
  • HTTP/3: runs on QUIC (UDP-based) with independent streams. Loss on one stream doesn't block others. 1-RTT handshake (0-RTT resumption). Connection ID survives IP changes.
  • QUIC integrates TLS 1.3: encryption is mandatory and combined with transport handshake. No plain-text QUIC exists in production.
  • Adoption: HTTP/2 is nearly universal (~99% of top-10K sites support it). HTTP/3 is ~35% and rising fast, with Google, Cloudflare, Meta, YouTube leading.
  • Server push (HTTP/2 feature) failed — Chrome removed support 2022. HTTP/3 doesn't have it. The replacement is 103 Early Hints.
  • The next version, HTTP/3+ or MASQUE, is being drafted — layers a VPN-like tunnel on top of QUIC.

References

  • RFC 7540 (2015) — HTTP/2 specification.
  • RFC 7541 (2015) — HPACK header compression.
  • RFC 9000 (2021) — QUIC v1 protocol.
  • RFC 9114 (2022) — HTTP/3 semantics.
  • Ilya GrigorikHigh Performance Browser Networking. Free online. The definitive treatment.
  • Robin Marx — HTTP/3 explainer blog posts (calendar.perfplanet.com). Best deep-dive for engineers.

Practice what you just read

Every foundation concept has a companion quiz to close the loop.