HTTP/2 is the second major version of the Hypertext Transfer Protocol, standardized in RFC 7540 in 2015 and revised as RFC 9113 in 2022, that keeps the semantics of HTTP (methods, status codes, headers) but replaces the text-based wire format with a binary framing layer. Among Internet protocols it sits between HTTP/1.1 and HTTP/3: it runs over a single TCP connection, usually protected by TLS, and carries many requests and responses at the same time as interleaved streams.
The protocol was developed from Google’s experimental SPDY protocol to solve one problem above all: HTTP/1.1 can only have one outstanding request per connection, so browsers opened six or more parallel connections per host and still waited in line. HTTP/2 removes that limit at the application layer while staying fully compatible with existing URLs, caches and application code.
How HTTP/2 frames and multiplexes traffic
HTTP/2 splits every message into frames, small binary units with a fixed 9-byte header that states the frame length, type, flags and a 31-bit stream identifier. A request and its response form one stream; client-initiated streams use odd numbers and server-initiated streams use even numbers. Because each frame carries its stream ID, frames from many streams can be interleaved on the same connection and reassembled correctly at the other end.
Every connection starts with a connection preface, the fixed string PRI * HTTP/2.0 followed by a SETTINGS frame, which confirms that both sides speak HTTP/2. Over TLS, the version is agreed during the handshake through ALPN with the identifier h2; the cleartext variant h2c exists but browsers do not support it. The table lists the frame types that do most of the work.
| Frame type | Purpose | Typical moment |
|---|---|---|
| HEADERS | Opens a stream and carries compressed headers | Start of every request and response |
| DATA | Carries the message body | After headers, often in many frames |
| SETTINGS | Announces connection parameters | Connection start and later changes |
| WINDOW_UPDATE | Grants more flow-control credit | While large bodies are transferred |
| RST_STREAM | Cancels one stream without closing the connection | User navigates away or request is aborted |
| GOAWAY | Starts graceful shutdown of the connection | Server restart or error |
| PING | Measures round-trip time and keeps the connection alive | Idle periods |
Header compression, flow control and prioritization
Headers in HTTP/1.1 are repeated as plain text on every request, and cookies alone can add kilobytes. HTTP/2 compresses them with HPACK (RFC 7541), which combines a static table of 61 common header fields, a dynamic table that both endpoints build during the connection, and Huffman coding of literal values. Repeated headers shrink to one or two bytes. HPACK was designed instead of generic compression because DEFLATE-based schemes in SPDY were exposed to the CRIME attack, which recovered secrets through compressed sizes.
Flow control works per stream and per connection with credit windows. The default initial window is 65,535 bytes, and the receiver raises it with WINDOW_UPDATE frames; servers that send large files commonly configure windows of several megabytes. The key settings are summarized below with their defaults and common values.
| Setting | Protocol default | Common practice |
|---|---|---|
| SETTINGS_MAX_CONCURRENT_STREAMS | Unlimited | 100 to 250 streams |
| SETTINGS_INITIAL_WINDOW_SIZE | 65,535 bytes | 64 KB to several MB |
| SETTINGS_MAX_FRAME_SIZE | 16,384 bytes | 16 KB, up to 16 MB allowed |
| SETTINGS_HEADER_TABLE_SIZE | 4,096 bytes | 4 KB to 64 KB |
| SETTINGS_ENABLE_PUSH | Enabled | Disabled by most clients |
The original specification also defined a dependency tree for stream priorities. It proved complex and inconsistently implemented, so RFC 9113 deprecated it in favor of the simpler Extensible Prioritization Scheme (RFC 9218), which signals urgency and incremental delivery in a priority header.
How HTTP/2 compares with HTTP/1.1 and HTTP/3
HTTP/2 changes how bytes travel, not what they mean, so the same request can be sent in any version. The decisive difference lies in where head-of-line blocking remains. HTTP/2 removes it between requests at the HTTP layer, but every stream still shares one TCP byte stream, so a single lost packet stalls all streams until it is retransmitted. HTTP/3 moves to QUIC over UDP precisely to remove that transport-level blocking.
| Property | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Wire format | Text | Binary frames | Binary frames |
| Transport | TCP | TCP | QUIC over UDP |
| Requests per connection | One at a time | Many multiplexed streams | Many multiplexed streams |
| Header compression | None | HPACK | QPACK |
| Head-of-line blocking | HTTP and TCP level | TCP level only | Largely removed |
| Encryption | Optional | Optional, TLS in practice | Always TLS 1.3 |
In practice, HTTP/2 is always used with TLS on the public web, because every major browser negotiates it only through ALPN on HTTPS connections. Many sites serve HTTP/2 and HTTP/3 side by side and advertise HTTP/3 through the Alt-Svc header or DNS HTTPS records.
Deploying and tuning HTTP/2
Enabling HTTP/2 is usually a single configuration switch on the web server, load balancer or CDN, provided TLS 1.2 or later and ALPN are available. The larger work is undoing HTTP/1.1 workarounds that now cost performance. The decision table shows which old habits to keep and which to drop.
| Old technique | Recommendation under HTTP/2 | Reason |
|---|---|---|
| Domain sharding | Remove or consolidate hosts | Extra connections defeat multiplexing and HPACK |
| Aggressive bundling | Bundle moderately | Small files no longer cost a connection slot |
| Image sprites | Prefer separate cached images | Granular caching beats one large file |
| Inlining assets | Inline only critical CSS | Inlined data cannot be cached separately |
| Server push | Use 103 Early Hints instead | Push was removed from major browsers |
Server push, which let a server send resources before the client asked, rarely improved real pages because it ignored the browser cache. Chrome removed support in 2022, and 103 Early Hints now serves the same goal by telling the browser what to preload. Operators should also set sensible concurrent stream limits and idle timeouts rather than accept defaults.
Limitations, attacks and common mistakes
The multiplexed design creates new denial-of-service surfaces. The 2023 Rapid Reset attack (CVE-2023-44487) opened and immediately canceled streams with RST_STREAM, generating record request rates with few connections. Earlier flaws abused PING floods, settings floods and HPACK decompression. Patched servers count and limit resets and other control frames per connection.
- Lossy networks such as congested mobile links can make HTTP/2 slower than several HTTP/1.1 connections, because one loss stalls every stream.
- Assuming HTTP/2 implies speed: a slow backend or oversized pages stay slow regardless of protocol.
- Terminating HTTP/2 at a proxy and speaking HTTP/1.1 to the origin is common and acceptable, but connection limits must then be tuned on the backend side.
- Request smuggling risks appear when a proxy downgrades HTTP/2 to HTTP/1.1 and fails to validate header values and content length.
Put simply
HTTP/2 is a faster way for a browser and a website to exchange the same information. With the older version, a browser had to ask for one file, wait for it, and only then ask for the next one on that line. HTTP/2 lets it ask for everything at once over one line and receive the pieces mixed together, each labeled so it can be sorted on arrival.
A good comparison is a delivery truck. Instead of sending one truck per parcel, HTTP/2 packs many labeled parcels into one truck. The contents of the parcels do not change at all, only the way they are transported.
In practice
A small online shop serves a product page with about 80 resources: scripts, style sheets, product photos and fonts. Under HTTP/1.1 its pages needed six connections per host plus a second image domain created for sharding, and the browser still queued requests on a mobile connection with a round-trip time of about 100 milliseconds.
The team enables HTTP/2 on its load balancer, removes the separate image domain so all requests share one connection and one header table, and splits a large JavaScript bundle into a few cacheable files. Repeat visitors now download only changed files, and the waterfall shows requests starting in parallel instead of in queues. The result is a noticeably shorter time to first render on mobile, without any change to application code.