HTTP/1.1 vs HTTP/2 vs HTTP/3: Differences and How to Enable Them
Multiplexing, header compression and QUIC — what each version changes, and how to enable and verify it.
The same HTML, CSS and images can load dramatically faster or slower depending on which HTTP version carries them. HTTP/1.1 still queues requests one at a time per connection, HTTP/2 multiplexes dozens of requests over a single TCP connection, and HTTP/3 replaces TCP entirely with QUIC running over UDP. This guide explains exactly what changed between the three versions, why it changed, and how to enable and verify HTTP/2 and HTTP/3 on your own server.
If you just want to know what your site speaks today, run your domain through the HTTP/2 & HTTP/3 support checker first — the rest of this article will make more sense with that result in hand.
Three problems that made HTTP/1.1 slow
- One request per connection, six connections per host — an HTTP/1.1 connection handles a single request at a time; the next one waits for the previous response. Browsers work around this by opening up to six parallel TCP connections per hostname, which is nowhere near enough for a modern page with dozens of assets.
- Head-of-line (HOL) blocking — if the response at the front of the queue is slow (say, a large image), everything behind it on that connection stalls. Pipelining was specified but effectively no browser ever shipped it, precisely because of this problem.
- Uncompressed, repeated text headers — headers like
CookieandUser-Agentare re-sent in full plain text on every single request. On cookie-heavy sites that wastes several kilobytes per request.
An entire generation of workarounds grew around these limits: domain sharding (splitting assets across img1.example.com, img2.example.com to multiply the connection budget), CSS sprites, and giant concatenated JS/CSS bundles. As we will see, those tricks turn into anti-patterns once HTTP/2 is on.
HTTP/2 — one TCP connection, many streams
Standardized in 2015, HTTP/2 changed four things that matter.
- Binary framing — the text protocol is replaced by small binary frames, which are faster and less ambiguous to parse.
- Multiplexing — many independent streams share one TCP connection, so dozens of requests fly in parallel. The six-connection limit and request queuing disappear in one stroke.
- HPACK header compression — headers already sent are replaced by index references. From the second request on, cookies and user-agent strings are no longer retransmitted, shrinking header overhead from kilobytes to tens of bytes.
- Stream prioritization — render-blocking resources such as CSS and fonts can be weighted above images so they arrive first.
One weakness remains, though. There are many streams but still one TCP connection. When a single packet is lost, TCP must retransmit it before delivering anything that arrived after it — so data for every stream sits in the kernel buffer waiting. HTTP/2 removed HOL blocking at the application layer but inherited it at the transport (TCP) layer. On reliable wired networks this rarely matters; on lossy mobile networks HTTP/2 can actually fall behind HTTP/1.1, whose six connections fail independently.
HTTP/3 — QUIC replaces TCP
HTTP/3 (RFC 9114, 2022) attacks that last problem by swapping the transport itself: instead of TCP it runs over QUIC, built on top of UDP.
- Per-stream loss recovery — QUIC understands streams at the transport layer. A lost packet stalls only the stream whose data it carried; all other streams keep flowing. TCP-style HOL blocking is gone.
- Faster handshakes and 0-RTT — TCP plus TLS 1.3 needs two round trips to set up a fresh connection; QUIC merges transport and crypto negotiation into one RTT. On a repeat visit it can resume with 0-RTT, putting the HTTP request into the very first packet.
- Connection migration — a TCP connection is identified by its IP/port 4-tuple, so switching from Wi-Fi to LTE kills it. QUIC identifies connections by a connection ID, so downloads survive a network change.
- QPACK header compression — HPACK reworked so it stays correct when QUIC delivers streams out of order.
Side-by-side comparison and a worked example: 30 assets
| Aspect | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Transport | TCP | TCP | QUIC (UDP) |
| Multiplexing | None (6 connections as a workaround) | Streams | Streams |
| HOL blocking | Per request (severe) | Remains at TCP layer | Effectively eliminated |
| Handshake (new connection) | 2–3 RTT (TCP+TLS) | 2 RTT (TCP+TLS 1.3) | 1 RTT, 0-RTT on resumption |
| Header compression | None (plain text) | HPACK | QPACK |
| Network switch (Wi-Fi→LTE) | Connection drops | Connection drops | Survives (migration) |
Worked example — imagine a page with 30 assets (2 CSS, 5 JS, 23 images) on a 50ms RTT link. Over HTTP/1.1 the browser splits them across six connections, so they load in at least five sequential batches (30 ÷ 6); each batch costs at least one RTT, adding 250ms+ of pure queueing on top of six separate TCP+TLS handshakes. Over HTTP/2 the browser fires all 30 requests at once down one warm connection and the responses interleave, so total time approaches the download time of the largest asset plus a single RTT. You can see the real-world gap by timing the same URL with the response time tool and comparing TTFB and total duration.
How to enable it — and how to verify
Enabling HTTP/2 (nginx) — HTTPS is a de facto prerequisite, since browsers only negotiate h2 over TLS.
- Older nginx:
listen 443 ssl http2; - nginx 1.25.1+: keep
listen 443 ssl;and addhttp2 on;(the listen-flag form is deprecated) - Apache uses
Protocols h2 http/1.1; most CDNs (Cloudflare and friends) enable h2 by default
Enabling HTTP/3 takes a little more.
- Run nginx 1.25+ built with QUIC support, or front the site with an HTTP/3-capable CDN
- Add
listen 443 quic reuseport;andhttp3 on;alongside your existinglisten 443 ssl; - Advertise h3 to browsers with an
Alt-Svcresponse header:add_header Alt-Svc 'h3=":443"; ma=86400'; - Open UDP port 443 inbound in your firewall or security group — leaving only TCP 443 open is the single most common mistake
Browsers connect over HTTP/2 first, read the Alt-Svc header, and only then upgrade to HTTP/3 for subsequent requests. Check that the header is actually being served with the HTTP headers inspector, then confirm the protocol negotiation end to end with the HTTP/2 & HTTP/3 checker.
HTTP/1.1-era tricks that hurt you under h2
- Domain sharding — with one connection doing all the work, extra shard domains only add DNS lookups and TCP/TLS handshakes, and they split the HPACK compression context. Consolidate assets onto one hostname.
- Mega-bundles and sprites — cram everything into one file and a one-icon change invalidates the whole cache. With multiplexing, the per-request cost of small files is nearly zero, so moderately granular files with long cache lifetimes win.
- Aggressive inlining — inlining critical CSS is still fine, but inlining cacheable assets into HTML throws away repeat-visit performance.
Frequently asked questions
Is HTTP/2 enough, or should I deploy HTTP/3 as well?
Does HTTP/2 strictly require HTTPS?
I enabled HTTP/3 but browsers keep using h2. Why?
What should I do with existing domain sharding when I move to HTTP/2?
Should I use HTTP/2 Server Push?
How do I see which HTTP version my site is using right now?
Tools to use with this guide
Related guides
- Core Web Vitals (LCP, CLS, INP) Improvement ChecklistWhat LCP, CLS and INP measure, and a practical checklist to improve each score.
- 301 vs 302 vs 307/308: Choosing the Right RedirectThe difference between redirect status codes and how to pick the right one for SEO and method preservation.