HTTP/2, despite being older than you might think, is still a surprisingly misunderstood protocol, and most people assume it’s just "faster HTTP/1.1" when its real magic lies in how it fundamentally changes how requests are handled.

Let’s see it in action. Imagine two clients, both trying to fetch the same small HTML page and a few images from a server.

HTTP/1.1 Scenario:

Client -> Request HTML (GET /index.html)
Server -> Response HTML
Client -> Request Image 1 (GET /image1.jpg)
Server -> Response Image 1
Client -> Request Image 2 (GET /image2.png)
Server -> Response Image 2
Client -> Request Image 3 (GET /image3.gif)
Server -> Response Image 3

Notice how each request is a separate, distinct conversation. Even if the server has the data ready, it can only send one thing at a time per connection. If the HTML is large, those images have to wait. This is "head-of-line blocking" at the request level.

HTTP/2 Scenario:

Client -> Initiates connection (with HPACK headers)
Client -> Request HTML (GET /index.html)
Client -> Request Image 1 (GET /image1.jpg)
Client -> Request Image 2 (GET /image2.png)
Client -> Request Image 3 (GET /image3.gif)
Server -> Response HTML (Frame 1)
Server -> Response Image 1 (Frame 2)
Server -> Response Image 2 (Frame 3)
Server -> Response Image 3 (Frame 4)

This looks like a lot of requests sent at once, right? But it’s not. HTTP/2 takes all those requests and breaks them down into small, independent frames. These frames are then multiplexed over a single TCP connection. The server can receive frames from different requests in any order, process them, and send back frames for different responses interleaved.

The core problem HTTP/2 solves is the inefficiency of making many separate TCP connections and the head-of-line blocking inherent in HTTP/1.1’s request-response model. HTTP/1.1 required a new TCP connection (or reuse of an existing one) for each request/response pair, and even with keep-alive, it could only send one response per connection at a time. If a large file was being sent, smaller, faster resources had to wait. This was particularly painful on high-latency networks where establishing new connections took significant time.

HTTP/2’s solution is binary framing. Instead of plain text, requests and responses are broken into binary frames. Each frame has a type (e.g., HEADERS, DATA, RST_STREAM), a stream ID (which identifies which logical request/response it belongs to), and a length. This allows for:

  1. Multiplexing: Multiple requests and responses can be active on a single TCP connection simultaneously. The client and server can send frames for different streams in any order, and the receiving end reassembles them based on the stream ID. This eliminates HTTP/1.1’s head-of-line blocking at the request level.
  2. Header Compression (HPACK): HTTP/1.1 headers were repetitive and verbose. HPACK compresses these headers, significantly reducing the amount of data sent, especially on initial requests. It uses dynamic tables to remember previously sent headers, allowing subsequent headers to be represented by short indices.
  3. Server Push: A server can proactively send resources to the client that it anticipates the client will need, without the client explicitly requesting them. For example, when a client requests an HTML page, the server might also push the associated CSS and JavaScript files, knowing they’ll be needed to render the page.

When does each win?

  • HTTP/2 wins overwhelmingly for typical web browsing: Loads of small assets, dynamic content, and the need for speed on modern, often mobile, networks. The multiplexing and header compression make a massive difference.
  • HTTP/1.1 might still be preferred in very specific, niche scenarios:
    • Extremely high-latency, low-bandwidth networks where TCP overhead is still a killer: While HPACK helps HTTP/2, TCP itself has overhead. If you’re on a connection where even a single TCP handshake and its acknowledgments are a significant chunk of your usable bandwidth, and you only have a single large file to transfer, HTTP/1.1 might be marginally simpler. This is rare.
    • APIs with very few, very large file transfers: If your API exclusively deals with transferring one massive file (e.g., a video upload/download) per connection, and you don’t have many concurrent requests, the benefits of HTTP/2’s multiplexing are less pronounced. However, even here, header compression can still offer a slight advantage, and the underlying TCP optimizations in HTTP/2 are still beneficial.
    • Legacy systems that don’t support HTTP/2: This is the most common reason you’d see HTTP/1.1 used today.

The most surprising thing most people miss is that HTTP/2’s multiplexing doesn’t eliminate TCP’s head-of-line blocking. If a single TCP packet containing frames for multiple HTTP/2 streams is lost, all those streams are blocked until that packet is retransmitted. This is why HTTP/3, which uses QUIC (over UDP), is gaining traction—it moves stream multiplexing out of the transport layer, so packet loss on one stream doesn’t affect others.

The next concept to explore is how HTTP/3 addresses the remaining transport-level head-of-line blocking.

Want structured learning?

Take the full Http2 course →