Introduction

Every time you open a web page your browser is secretly juggling dozens of files: HTML, CSS, scripts, images, fonts. For decades all of them shared a single TCP connection, and TCP has a painful rule — if one packet goes missing, nothing moves forward until it arrives. One stalled image freezes the line for every other resource. Networking engineers called this head-of-line blocking.

QUIC (now standardised as RFC 9000 and the foundation of HTTP/3) was Google's answer, born inside Chrome around 2012 and handed to the IETF in 2016. The idea is conceptually bold: throw TCP away and run everything directly over UDP. UDP has no built-in ordering or retransmission, so QUIC implements its own — but cleverly, with one stream per resource. When a packet for stream 3 goes missing, streams 1, 2 and 4 keep flowing.

QUIC also folds in TLS 1.3 from the start, so the cryptographic handshake and the transport setup happen simultaneously instead of one after another. A brand-new connection costs just 1 round-trip to reach encrypted data; a returning client can send data with 0 round-trips (0-RTT), attaching its request to the very first packet.

The result is a protocol that looks like TCP + TLS from the application's point of view but behaves like a sports car on a bumpy road: individual potholes (lost packets) barely slow it down, and it gets up to speed in almost no time.

Try It: Stream Isolation

The demo below simulates four parallel streams downloading resources. In TCP mode a single stalled stream (one missing packet) blocks all streams behind it. In QUIC mode only the affected stream pauses — the rest complete on time.

<!-- {{c_demo_desc}} -->
<div class="controls">
  <div class="mode-toggle">
    <button id="btn-tcp" class="mode-btn active" type="button">TCP</button>
    <button id="btn-quic" class="mode-btn" type="button">QUIC</button>
  </div>
  <button id="btn-stall" type="button">{{btn_stall}}</button>
  <button id="btn-reset" type="button" class="ghost">{{btn_reset}}</button>
</div>
<div id="mode-label" class="mode-label">{{label_tcp}}</div>
<div id="streams" class="streams"></div>
<div id="status" class="status"></div>
/* {{c_css_desc}} */
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; margin: 0; color: #222; }
.controls { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin-bottom: .6rem; }
.mode-toggle { display: flex; border: 1px solid #1d3557; border-radius: 8px; overflow: hidden; }
.mode-btn { font: 600 14px system-ui, sans-serif; padding: .4rem .9rem; border: none;
            background: #fff; color: #1d3557; cursor: pointer; transition: background .15s; }
.mode-btn.active { background: #1d3557; color: #fff; }
button { font: 600 14px system-ui, sans-serif; padding: .4rem .9rem; border: 1px solid #1d3557;
         background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
.mode-label { font-size: .85rem; font-weight: 600; color: #555; margin-bottom: .5rem; }
.streams { display: flex; flex-direction: column; gap: .5rem; }
.stream-row { display: flex; align-items: center; gap: .6rem; }
.stream-name { width: 70px; font-size: .82rem; font-weight: 600; color: #333; text-align: right; flex-shrink: 0; }
.track { flex: 1; height: 22px; background: #e5e9ee; border-radius: 6px; overflow: hidden; position: relative; }
.bar { height: 100%; border-radius: 6px; transition: width .08s linear; }
.bar-0 { background: #3a86ff; }
.bar-1 { background: #06d6a0; }
.bar-2 { background: #f4a261; }
.bar-3 { background: #e63946; }
.stalled .bar { background: #adb5bd !important; }
.pct { width: 36px; font-size: .8rem; color: #555; text-align: right; flex-shrink: 0; }
.done-tick { width: 18px; flex-shrink: 0; text-align: center; font-size: .9rem; }
.status { font-size: .95rem; font-weight: 600; min-height: 1.4em; margin-top: .6rem; }
.status.ok { color: #0a7d33; }
.status.running { color: #555; }
.status.blocked { color: #c92f3c; }
// Code not found

Click Stall a stream to inject a packet loss, then toggle between TCP and QUIC to feel the difference. Notice that in QUIC the three healthy streams finish well before the stalled one resumes, while in TCP the entire transfer halts until the missing packet is retransmitted.

How QUIC Really Works

QUIC's design sits on a handful of elegant ideas:

Independent streams. Every resource gets its own stream ID — an integer the sender assigns. Lost packets belong to one stream; the receiver can process all other streams while waiting for the retransmission. Compare this to TCP, where a single byte stream means the receiver's buffer stalls at the gap.

Connection IDs instead of socket pairs. In TCP a connection is defined by (src_IP,src_port,dst_IP,dst_port)(src\_IP, src\_port, dst\_IP, dst\_port). Change your IP (say, switching from Wi-Fi to mobile data) and the connection dies. QUIC uses an opaque connection ID chosen by both sides, so the same logical connection survives a network switch — a feature called connection migration.

Integrated TLS 1.3. TCP opens the socket first, then TLS negotiates on top. QUIC merges both handshakes: the client sends its TLS "ClientHello" inside the first QUIC packet. The server can reply with encrypted data in the next packet. Result: 1-RTT for new connections. A returning client that still holds a session ticket can piggyback encrypted data on the very first flight — 0-RTT.

Loss detection without ambiguity. TCP sequence numbers make retransmissions ambiguous (did the ACK cover the original or the retransmit?). QUIC assigns each packet a monotonically increasing packet number, so an ACK is never ambiguous and the sender can estimate round-trip time far more accurately.

Head-of-line blocking: gone by design. Because streams are independent, nn simultaneous streams each lose at most their own packets. The probability that all streams stall simultaneously falls exponentially with nn. In practice, over a link with pp packet-loss rate, the fraction of time QUIC is fully blocked is roughly pnp^{n}, versus pp for TCP regardless of multiplexing.

These primitives make QUIC measurably faster than TCP+TLS in the real world — Google reported a 3 % reduction in search latency and a 30 % reduction in buffering for YouTube when they deployed QUIC internally.

Where It Matters

QUIC is already the backbone of a large chunk of the internet:

  • HTTP/3: the third version of the Hypertext Transfer Protocol is literally QUIC with an HTTP mapping on top. As of 2024, roughly 30 % of all web traffic uses HTTP/3. Every major CDN (Cloudflare, Fastly, Akamai) and cloud provider supports it.
  • Google services: Search, YouTube, Gmail and Google Drive have all been on QUIC for years. It is the default transport in Chrome.
  • Mobile networks: packet loss is common on cellular links. QUIC's tolerance for isolated losses — and its connection migration when the device switches towers — makes a real difference to perceived latency.
  • WebTransport: a browser API built on QUIC that lets web applications open arbitrary bidirectional or unidirectional streams to a server, without the overhead of WebSockets. Game servers and collaborative tools are early adopters.
  • Media streaming: video players that need to fetch many small chunks in parallel benefit enormously from independent streams. A hiccup in one quality level's download does not delay the next segment of the video.

The same ideas behind QUIC — independent multiplexed streams, connection identifiers, fast handshakes — are now influencing designs well beyond the web, from QUIC-based VPNs to low-latency messaging protocols.

Conclusion

QUIC's lesson is that sometimes the right answer to a 40-year-old protocol's problems is not a patch — it is a clean slate. By moving to UDP and reimplementing only the things TCP gets right (reliability, flow control, congestion control) while dropping what it gets wrong (head-of-line blocking, rigid socket identity, layered TLS), QUIC unlocked gains that tweaking TCP could never deliver.

The deeper principle is the same one that shows up across networking and systems: multiplexing independent channels beats forcing everything through a single shared queue. A single stalled stream is a local event; in TCP it becomes a global one. QUIC keeps failures local.

If you have ever wondered why your browser loads most of a page instantly but one image hangs for a second, you have felt head-of-line blocking. And if that image never hangs anymore — you may have QUIC to thank.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/quic-protocol/Content licensed under CC BY-NC 4.0.