NGINX: HTTP/2 vs HTTP/3 β What Actually Changes Under the Hood?
HTTP/2 and HTTP/3 both improve web performance, but use fundamentally different transports. HTTP/2 runs over TCP, while HTTP/3 uses QUIC over UDPβchanging connection handling, packet processing, streams, congestion control, and NGINX worker behavior.
HTTP/2 and HTTP/3 were both designed to make the modern web faster, but they take fundamentally different approaches to transporting HTTP traffic.
If you run NGINX, the distinction is especially important because enabling HTTP/3 is not simply a matter of changing http2 to http3. HTTP/2 runs over TCP, while HTTP/3 runs over QUIC, which runs over UDP.
That difference changes the connection model, packet handling, congestion control, stream behavior, and even how NGINX workers can process incoming traffic.
HTTP/2: HTTP Multiplexing Over TCP
HTTP/1.1 traditionally required multiple connections or techniques such as pipelining to efficiently retrieve many resources.
HTTP/2 changed that model.
Instead of treating every request as an independent connection, HTTP/2 uses a single TCP connection containing multiple streams, which are independent logical channels used to carry individual requests and responses concurrently.
In essence:
TCP CONNECTION
β
ββββββββββββββββΌβββββββββββββββ
β β β
Stream 1 Stream 3 Stream 5
β β β
HTML CSS JSThis is called multiplexing.
A browser can request the HTML document, CSS, JavaScript, images, fonts, and other resources concurrently over the same connection.
NGINX therefore does not need a separate TCP connection for every HTTP/2 request.
A simplified NGINX configuration looks like:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
...
}The important part is:
http2 on;http2 on; enables HTTP/2 for the server block. It tells NGINX that clients connecting to that server over HTTPS may use HTTP/2 instead of HTTP/1.1, provided the client supports it and TLS negotiation selects HTTP/2.
The connection itself is still TCP.
Client
β
β HTTPS
β TCP
βΌ
NGINX :443
β
βββ HTTP/2
βββ Stream 1 β Request / Response
βββ Stream 3 β Request / Response
βββ Stream 5 β Request / Response
βββ Stream 7 β Request / ResponseThe TCP connection remains the underlying transport. HTTP/2 changes how HTTP messages are multiplexed over that connection.
What http2 on;actually changes
Without HTTP/2:
HTTPS
β
βΌ
TCP connection
β
βββ HTTP/1.1 requestsOne important point
http2 on; does not mean βuse HTTP/2 only.β
A client that doesnβt support HTTP/2 can still connect using HTTP/1.1. During the TLS handshake, ALPN is used to negotiate the protocol.
In essence:
TLS + ALPN
β
βββββββββ΄ββββββββ
βΌ βΌ
HTTP/2 HTTP/1.1
β
TCP connectionHTTP/2 = TCP + HTTP/2 streams
The HTTP/2 Problem: TCP Head-of-Line Blocking
HTTP/2 solved a major problem with HTTP/1.1, but it inherited a limitation from TCP.
TCP presents applications with an ordered byte stream.
HTTP/2 solved a major problem with HTTP/1.1 by allowing multiple requests and responses to share a single connection. However, it inherited an important limitation from the TCP transport underneath it.
TCP presents applications with a single, ordered byte stream. Data can arrive out of order at the network level, but TCP must reassemble that data and deliver the byte stream to the application in order.
Consider an HTTP/2 connection carrying several independent streams:
ONE TCP CONNECTION
βββββββββββββββββββββββββββββββββββββββββββββββββββββββΊ
Stream A ββββββββ[A1][A2][A3][A4]βββββββββββββββΊ
Stream B ββββββββ[B1][B2][B3][B4]βββββββββββββββΊ
Stream C ββββββββ[C1][C2][C3][C4]βββββββββββββββΊ
Stream D ββββββββ[D1][D2][D3][D4]βββββββββββββββΊ
β²
β
TCP data lostSuppose the TCP segment containing part of Stream A is lost. Data belonging to Streams B, C, and D may still reach the server successfully, but TCP cannot simply deliver bytes beyond the missing portion to the application while maintaining its required ordered byte stream.
The later data can be received and buffered, but the missing data must be recovered before TCP can provide a continuous stream to the application.
This creates TCP-level head-of-line (HOL) blocking.
The important point is that HTTP/2 streams are logically independent, but TCP does not know about those streams. From TCPβs perspective, everything is simply part of one ordered byte stream.
HTTP/2 therefore provides excellent multiplexing at the HTTP layer, but all of those streams ultimately depend on the same TCP connection.
HTTP/3 takes a fundamentally different approach by moving stream multiplexing into QUIC, where streams are independently managed at the transport layer.
HTTP/3: HTTP Over QUIC
HTTP/3 does not run over TCP.
It runs over QUIC, and QUIC runs over UDP.
The stack becomes:
HTTP/3
β
βΌ
QUIC
β
βΌ
UDP
β
βΌ
IPInstead of:
HTTP/2
β
βΌ
TLS
β
βΌ
TCP
β
βΌ
IP
This is the most important architectural difference between HTTP/2 and HTTP/3.
HTTP/2 relies on TCP for transport and uses TLS as a separate security layer, while HTTP/3 uses QUIC as its secure, multiplexed transport over UDP.
QUIC Is More Than βUDPβ
It is tempting to describe HTTP/3 as simply βHTTP over UDP.β
That is technically true at a very low level, but it misses the important part.
UDP itself does not provide:
- reliable delivery
- ordering
- congestion control
- connection management
- retransmission
- encrypted transport
QUIC implements these capabilities above UDP. It provides a modern, encrypted transport layer while using UDP as its underlying datagram mechanism.
So the architecture is better understood as:
ββββββββββββββββββββββββββββββββ
β HTTP/3 β
β HTTP semantics β
ββββββββββββββββ¬ββββββββββββββββ
β
ββββββββββββββββΌββββββββββββββββ
β QUIC β
β Streams β
β Reliable delivery β
β Retransmission β
β Flow control β
β Congestion control β
β Connection management β
β TLS 1.3 integration β
ββββββββββββββββ¬ββββββββββββββββ
β
ββββββββββββββββΌββββββββββββββββ
β UDP β
β Datagram transport β
ββββββββββββββββ¬ββββββββββββββββ
β
ββββββββββββββββΌββββββββββββββββ
β IP β
ββββββββββββββββββββββββββββββββUDP provides the basic datagram transport. QUIC builds the sophisticated transport functionality on top of it, and HTTP/3 runs on top of QUIC.
That distinction is essential: HTTP/3 is not βHTTP directly over UDP.β It is HTTP/3 over QUIC over UDP.
HTTP/3 Streams Are Independent
This is one of the most important differences between HTTP/2 and HTTP/3.
HTTP/3 uses QUIC streams, and each stream has its own ordered delivery. A packet loss affecting one stream does not necessarily block unrelated streams from continuing.
In essence:
QUIC CONNECTION
β
βββββββββββββββΌββββββββββββββ
β β β
Stream 1 Stream 3 Stream 5
β β β
HTML CSS JS
β β β
βΌ X βΌ
received packet loss received
β
β
retransmit
β
βΌ
CSS dataSuppose a QUIC packet carrying part of the CSS stream is lost. QUIC can detect the loss and retransmit the missing data, while data belonging to the HTML and JavaScript streams can continue to be delivered if it has arrived successfully.
The browser therefore does not necessarily have to wait for the missing CSS data before receiving additional data from unrelated streams.
This is a major architectural advantage of QUIC: loss on one stream does not inherently create transport-level head-of-line blocking for every other stream in the connection.
That is fundamentally different from HTTP/2 over TCP, where all HTTP/2 streams share the same ordered TCP byte stream.
So, Whatβs the Fuzz?
Okay, we know how HTTP/3 works.
But whatβs the big deal?
Going deep into QUIC internals, packet recovery, congestion control, and connection migration is beyond the scope of this article. The important takeaway is that HTTP/3 gives the web a modern transport layer designed to reduce latency, handle packet loss more gracefully, and keep connections moving efficiently.
But this isnβt just theoretical.
What Websites Use QUIC?
QUIC already powers a growing part of the modern web through HTTP/3. Major platformsβincluding SNUBmonkeyβ’, Google, YouTube, Facebook, and sites using CDNs like Cloudflareβsupport it.
QUIC isnβt waiting for the future. The future is already using it.
What matters is what HTTP/3 can actually do for real-world applications:
1. Better on Bad Networks
HTTP/3 handles packet loss more efficiently, so a problem with one stream doesnβt necessarily slow down the others.
2. Better for Mobile
Cellular networks can be unpredictable. HTTP/3 is designed to handle latency, packet loss, congestion, and changing network conditions more efficiently.
3. Faster Connections
QUIC combines transport setup and TLS 1.3, reducing the time needed to establish a secure connection.
4. Survives Network Changes
QUIC can keep a connection alive when a device switches networks, such as moving from Wi-Fi to cellular.
5. Less Head-of-Line Blocking
In HTTP/2, multiple requests share one TCP connection. If a packet is lost, TCP may hold up data that arrived after itβeven if that data belongs to a different request.
6. Great for Modern Apps
APIs, streaming, large downloads, live updates, and other applications with multiple simultaneous data flows can benefit from QUICβs stream architecture.
7. HTTP/2 Still Has a Place
HTTP/3 doesnβt replace HTTP/2 overnight. NGINX can serve both:
TCP :443 β HTTP/2
UDP :443 β HTTP/3 / QUICClients that support HTTP/3 can use QUIC, while everyone else can continue using HTTP/2.
The Point?
HTTP/3 isnβt simply βfaster HTTP.β
Itβs about making applications more responsive and resilient when the network isnβt perfect.
Thatβs the real fuzz.
HTTP/3 isnβt about replacing HTTP/2βitβs about building a more resilient, modern transport for todayβs web. The real benefits show up when networks are slow, lossy, congested, or constantly changing.
Thanks for readingβand as always, keep experimenting, breaking things safely, and learning.
See you on the next one.