HTTP/2 (RFC 9113) keeps HTTP/1.1's semantics (methods, status codes, headers) but completely redesigns how bytes move on the wire. The goal was to handle many requests concurrently over a single TCP connection with no stalls — eliminating the bottleneck of HTTP/1.1 handling one request at a time per connection (and the wasteful workaround of browsers opening six connections per domain).
Binary framing
The most fundamental change is turning text-based HTTP into binary frames. All communication is chopped into frames with a fixed 9-byte header. Each frame carries a type (HEADERS, DATA, SETTINGS, WINDOW_UPDATE, RST_STREAM, …) and the Stream Identifier it belongs to.
+-----------------------------------------------+
| Length (24) |
+---------------+---------------+---------------+
| Type (8) | Flags (8) |
+-+-------------+---------------+-------------------------------+
|R| Stream Identifier (31) |
+=+=============================================================+
| Frame Payload ... |
+---------------------------------------------------------------+
Streams and multiplexing
A stream is a logical channel for one request/response exchange, each with its own Stream ID. Interleaving frames from many streams over a single TCP connection is multiplexing. The receiver reassembles by looking at each frame's Stream ID. This erases HTTP/1.1's application-layer head-of-line blocking, where one slow response stalled everything behind it, and lets a single connection carry hundreds of requests in parallel.
HPACK header compression
HTTP request headers like User-Agent and Cookie repeat almost identically on every request — pure waste. HPACK (RFC 7541) compresses them. It maintains a static table of common headers and a dynamic table that both ends update per connection, then references headers by table index instead of the literal string. String values are further shrunk with Huffman coding. (HTTP/1.1 had no header compression at all.)
- Binary framing: frame-based parsing is fast and unambiguous versus text.
- Multiplexing: many streams over one connection → far fewer connections.
- HPACK: repeated headers compressed to indexes.
- Stream prioritization: hints about which stream to send first.
- Flow control: per-stream and per-connection receive rate limiting.
- Server push: server pre-sends resources before they're requested (now deprecated).
Server push (deprecated), prioritization, flow control
Server push let a server pre-send the CSS/JS a page needs before the client asked, but it often re-sent already-cached resources and delivered little benefit, so major browsers removed support, effectively deprecating it (today 103 Early Hints and preload fill that role). Stream prioritization hints at which stream to send first; the original tree-based scheme was complex and underused, and the trend is toward a simpler priority scheme. Flow control uses WINDOW_UPDATE frames to manage per-stream and per-connection receive windows so a fast sender can't overwhelm a slow receiver.
h2c and the remaining limit: TCP head-of-line blocking
In practice HTTP/2 is negotiated over TLS via ALPN h2. Cleartext HTTP/2 is called h2c, but browsers don't support it, so it appears mainly in service-to-service traffic. And although HTTP/2 removes application-layer HoL, the transport-layer limit remains. Because every stream shares one TCP connection, a single lost packet forces TCP — to guarantee ordering and retransmit — to stall the data of all the following streams too. That is TCP head-of-line blocking, and solving it at the root is exactly why UDP-based QUIC (HTTP/3) was created.