Konrad Kowalski (rootsher)Principal Platform & Reliability Architect000011010011111101001001111111100001000100101001

HTTP/3 and QUIC: Same HTTP, Different Transport

date
category
Networking
also in
Frontend
reading
2 min / 340 words

HTTP/2 solved an important problem:

text
many HTTP requests
-> many independent HTTP streams

But the streams still shared one TCP connection.

HTTP/3 changes the layer below HTTP.

text
HTTP/2
  |
  v
TCP
  |
  v
TLS

HTTP/3
  |
  v
QUIC
  |
  v
UDP

QUIC integrates the transport and cryptographic mechanisms needed for secure communication.

HTTP semantics stay

The frontend still writes:

js
fetch("/api/users");

The backend still semantically sees:

text
GET /api/users

All of these still exist:

text
status codes
headers
cache semantics
content

HTTP/3 is not a new API model.

It is a new mapping of HTTP semantics onto a transport.

Streams are more independent

QUIC has many logical streams at the transport level.

If data on one stream is lost, retransmitting that stream does not have to block delivery of data on other streams.

Simplified:

text
HTTP/2 over TCP

loss
  |
  v
shared TCP byte stream waits
  |
  v
multiple HTTP streams can stall

versus:

text
HTTP/3 over QUIC

loss in stream A
  |
  v
stream A waits for recovery

stream B can continue

That removes transport-level head-of-line blocking between independent streams.

It does not remove application latency

If the frontend does:

js
const user = await fetch("/user");
const orders = await fetch(`/users/${user.id}/orders`);

we have a dependency:

text
request A
  |
  v
response A
  |
  v
request B

HTTP/3 will not fix that.

A network protocol does not remove serialization created by the application.

Which matters for performance debugging.

A better transport does not replace a correct dependency graph.

Connection establishment

QUIC can reduce the cost of establishing secure communication compared with separate TCP and TLS stages.

For returning connections 0-RTT is also possible under certain conditions.

But 0-RTT has security and replay limitations, so it should not be thought of as:

text
every HTTP/3 request starts instantly

It is an optimization of one specific stage of connection setup.

Connection migration

A TCP connection is tightly bound to the classic tuple of addresses and ports.

QUIC uses connection IDs, which makes it easier to keep a logical session alive when the network path changes.

A practical case:

text
phone on Wi-Fi
  |
  v
switch to cellular

This matters especially for mobile devices.

The frontend does not steer it directly, but it feels the effect as a more resilient transport layer.

Does the frontend have to detect HTTP/3?

Usually not.

Application code should rely on HTTP semantics:

text
method
status
headers
body

The browser and the infrastructure negotiate the transport protocol.

DevTools can show the protocol in use, which helps with performance analysis.

But business logic should not look like this:

js
if (httpVersion === 3) {
  ...
}

That is exactly the strength of separating the layers.

Now we can put them all together and see what really happens after a single fetch().