Beyond Code & Karma · Networking

HTTP Multiplexing

Many streams, one connection. How HTTP/2 interleaves dozens of requests as frames to defeat HTTP/1.1's head-of-line blocking — and where HTTP/3 and QUIC carry the idea further. The transport choice that decides how fast a page paints.

Interactive Deep Dive · Networking

One slow pilgrim should not block the road.
The whole point is — don't wait in line.

A modern page pulls dozens of resources — HTML, CSS, JavaScript, fonts, images. Multiplexing is how a protocol lets those requests share one connection at the same time instead of queuing. HTTP/1.1 sends one request-response per connection at a time, so a slow response blocks everything behind it — head-of-line blocking. HTTP/2 breaks each request into frames tagged with a stream ID and interleaves them over a single connection, so every stream makes progress together.

The Secret: the win isn't a faster network — it's removing the queue. HTTP/2 carries the same bytes over the same wire, but no request ever waits behind another. The bottleneck stops being the protocol and starts being the network itself.
A Connection
One transport pipe between client and server — a TCP+TLS socket (or a QUIC connection). Expensive to open; HTTP/2 needs only one per origin.
A Stream
One independent request/response, identified by a stream ID. Many streams live inside a single connection at once — the "many" carried by the "one".
Frames
Requests and responses are sliced into small framed chunks, each stamped with its stream ID, then interleaved on the wire and reassembled by stream at the far end.
Head-of-Line Blocking
One stuck item at the front of a queue holding up everything ready behind it. HTTP/1.1 suffers it per request; TCP suffers it per packet.

The one and the many — Indra's net, and the single ocean

Hindu Philosophy Parallel

In the Vedic image of Indra's net, reality is a vast web with a jewel at every knot, and each jewel reflects all the others — many distinct things, held as one fabric. The Upanishads say the many are strung on the one like beads on a single thread (sutra), as many rivers lose their names in one ocean without ceasing to be themselves. HTTP/2 is exactly this: unity-in-diversity on the wire.

The One — the connection
A single thread of Brahman: one connection on which every stream is strung and carried as one flow.
The Many — the streams
Each request a distinct jewel in Indra's net, reflecting all the others, never losing its own stream ID.
The Ford — HTTP/1.1
A narrow river-crossing where one slow pilgrim blocks the road — head-of-line blocking made into a place.

"Multiplexing is unity-in-diversity: the many made one, without any one losing its distinctness."

From a waterfall to interleaved frames

The clearest way to feel multiplexing is to look at the request waterfall — HTTP/1.1 serializes, HTTP/2 overlaps. Then check what your own origin actually negotiates.

The waterfall — serial vs interleaved

HTTP/1.1 opens roughly six connections and serializes requests inside each; HTTP/2 puts everything on one connection as interleaved frames:

waterfall.txt
# HTTP/1.1 — browser opens ~6 connections, requests serialize inside each.
# Each [====] is one request occupying its connection end-to-end.
conn-1  [==html==][===app.js===][==logo.png==]
conn-2  [==app.css==][==hero.jpg==]
conn-3  [==font.woff2==]
#         └─ a slow response holds the whole connection: head-of-line blocking.

# HTTP/2 — ONE connection, every request interleaved as frames.
conn-1  [html][css][js][img][font][js][img][html]...  # all in flight together
#         └─ no request waits behind another. App-layer HOL blocking is gone.
Why it works: every frame carries its stream ID, so the receiver can reassemble each response independently. Nothing waits for the resource ahead of it to finish — application-layer head-of-line blocking is gone.

Check it yourself — curl the protocol

ALPN negotiates h2 during the TLS handshake; HTTP/3 advertises itself with an alt-svc header and upgrades on the next visit:

check-protocol.sh
# Which wire protocol is an origin actually serving?
# -I = headers only; --http2 negotiates h2 over TLS via ALPN.
curl -I --http2 https://beyondcodekarma.in

# The status line names the protocol on the wire:
#   HTTP/2 200        ← one TCP + TLS connection, fully multiplexed

# HTTP/3 advertises itself in a response header, then upgrades:
#   alt-svc: h3=":443"; ma=86400
curl -I --http3 https://cloudflare.com

The four moves — a request's journey on HTTP/2

Request

A new request opens a stream with its own ID over the single existing connection — no new handshake, no new socket.

Frames

Headers and body are sliced into small frames, each stamped with that stream ID so it never loses its identity.

Interleave

Frames from every active stream are interleaved on the one connection, so all requests advance together — the many as one.

Reassemble

The receiver groups frames by stream ID and rebuilds each response independently. No stream waited in line for another.

Watch HTTP/2 overtake HTTP/1.1

Four requests race across the wire on each protocol, auto-playing. HTTP/1.1 sends them one at a time; HTTP/2 interleaves all four at once and finishes first.

Serial vs Multiplexed · 4 requests
⏸ Ready

The nuances that senior devs know

This is where the basic explainers stop. Here's the part that decides real-world tail latency.

PropertyHTTP/1.1HTTP/2HTTP/3
Connections / origin~6 parallel11 (QUIC)
MultiplexingNone — serial per connYes — interleaved framesYes — independent streams
App-layer HOL blockingYesNoNo
Transport HOL blockingPer connectionYes (one TCP stream)No (per-stream delivery)
TransportTCP + TLSTCP + TLSQUIC over UDP

HTTP/2 removes the application-layer queue, but it still rides a single TCP connection — and TCP delivers its byte stream strictly in order. If one packet is lost, the receiver must hold back every byte that arrived after it, including frames belonging to completely unrelated streams, until that one packet is retransmitted. So under packet loss, HTTP/2's "everything in parallel" becomes "everything frozen together". That is transport-layer HOL blocking, and it is the exact reason HTTP/3 exists.

HTTP/3 keeps multiplexing but swaps the transport for QUIC, built on UDP. QUIC implements its own loss recovery with independent streams — each stream carries its own delivery ordering. A packet lost on one stream stalls only that stream; the others keep flowing, because they were never waiting on it.

Bonus: QUIC folds the TLS handshake into connection setup (often 1-RTT or 0-RTT), so connections start faster and are encrypted by default — separate boats and a quicker launch.

HTTP/3's big win is under packet loss and on lossy or high-latency networks — mobile, congested links — where killing transport HOL blocking and using a faster handshake genuinely helps. On a clean, low-loss wired connection the difference is often small, and QUIC's user-space processing can cost slightly more CPU than the kernel's highly tuned TCP stack. It improves real-world tail latency; it is not a universal speed-up. Measure before assuming.

HTTP/1.1 hacks were all about beating the ~6-connection ceiling: domain sharding (serve assets from many subdomains to open more connections), image sprites, and concatenating CSS/JS into giant bundles. Under HTTP/2 these become counter-productive — sharding multiplies expensive connections and defeats a single congestion-control context, and mega-bundles hurt caching granularity. With cheap multiplexed streams, smaller, independently-cacheable files win.

It's the default transport for most of the modern web:

SystemWhat multiplexing buys it
CDNs (Cloudflare, Fastly)HTTP/2 & HTTP/3 at the edge — resilient delivery under real-world loss.
BrowsersOne connection per origin replaces six; better congestion control, faster paints.
gRPCBuilt directly on HTTP/2 streams for bidirectional, multiplexed RPC.
Mobile networksHTTP/3 contains packet-loss damage to one stream, smoothing tail latency.

The Karma of a shared boat

The Karma Connection

Multiplexing is the discipline of holding the many as one — the connection is the single thread, the streams are the jewels of Indra's net strung upon it. But to bind many fates to one vessel is also to share its karma:

karma.js
// One connection — the single thread on which the many are strung.
const conn = connect('h2');          // the one

// Many streams — distinct jewels in Indra's net, each reflecting
// all the others, yet all carried as a single interleaved flow.
streams.forEach(s => conn.send(s.frames));  // the many

// HTTP/1.1: the narrow ford — one slow pilgrim blocks the road.
// HTTP/2: the many made one, without losing their distinctness.

When the shared boat strikes a rock — a lost packet — all aboard are bound to wait together. That is shared karma: TCP head-of-line blocking. To give each pilgrim a separate boat (HTTP/3, QUIC) is not selfishness; it is the discipline of not entangling one soul's delay with another's journey. Bear your own loss, and let the others keep flowing.

"The many made one is grace; the one made to suffer for all is the cost. Choose the binding wisely." — interpreted for systems engineers 🙏

Multiplexing Trivia

Three questions. No cheating. Your karma is watching.

Question 1
HTTP/2 multiplexes many streams over one TCP connection. One packet is lost. What happens?
Question 2
Which layer of head-of-line blocking does HTTP/2 actually solve versus HTTP/1.1?
Question 3 — 🌶️ Spicy
Why does HTTP/3 run QUIC over UDP instead of just improving TCP?

The Six Truths of HTTP Multiplexing

One Connection
HTTP/2 needs a single connection per origin. One expensive handshake replaces six — and one congestion-control context.
Frames Carry Identity
Every frame is stamped with a stream ID, so interleaved chunks reassemble into the right response. That ID is what makes the many one.
No App-Layer Queue
Streams don't wait behind one another. Application-layer head-of-line blocking — HTTP/1.1's tax — is gone.
TCP Still Blocks
All streams share one in-order TCP byte stream, so one lost packet freezes them all. Multiplexing didn't reach the transport.
QUIC Gives Each a Boat
HTTP/3 makes streams independent over UDP. One stream's loss no longer stalls the rest — separate boats, separate karma.
Unity in Diversity
The connection is the one, the streams the many. Multiplexing holds them as a single flow without erasing any one's identity.

कर्म करो, फल की चिंता मत करो