HTTP/2 Header Compression Explainer
Explain how HPACK compresses repeated HTTP/2 headers.
Overview
Paste a sequence of HTTP/2 request or response headers and the explainer walks through how HPACK would compress them - which headers come from the static table, which from the dynamic table, and which are sent literally with or without Huffman coding. The byte breakdown shows where the bandwidth savings come from.
It's for developers and network engineers debugging HTTP/2 performance, optimising header sets, or just trying to understand why their :authority header doesn't show up in a packet capture. Reach for it when investigating slow connections, planning what headers to cookie-bake vs include per-request, or learning HPACK in the first place.
How it works
HPACK (RFC 7541) compresses headers by maintaining two indexed tables: a static table of 61 well-known header name/value pairs (:method GET, :status 200, content-encoding gzip), and a per-connection dynamic table that grows as headers are seen. New headers can be sent literally (full name and value), with a literal name and indexed value, or as a single index referring back to either table.
The explainer simulates the encoder's choices: a perfectly-matched header costs 1-3 bytes (an index); a partial match (known name, new value) costs the value plus a few bytes; a brand-new header costs its full literal representation. Huffman coding further shrinks string literals using a fixed table.
Examples
:method GET-> static table index 2 (1 byte on the wire).:path /-> static table index 4 (1 byte).content-type: application/json-> name from static table, value literal (~25 bytes Huffman-coded).- After the first request, dynamic table holds
content-type: application/json-> subsequent requests cost just 1-2 bytes for that header.
FAQ
Why does the first request cost so much more than later ones?
The dynamic table is empty at connection start, so every header is literal. As the table fills, repeated headers (cookies, user-agent, content-type) compress to a single index.
What's the size limit on the dynamic table?
HTTP/2 negotiates SETTINGS_HEADER_TABLE_SIZE per direction (default 4096 bytes). Newer connections to CDNs sometimes raise this.
Is HPACK the same in HTTP/3?
No - HTTP/3 uses QPACK (RFC 9204), which decouples the dynamic table updates from the stream order so head-of-line blocking can't stall it.
How can I shrink my header footprint?
Use static-table headers when possible, keep cookies short, avoid per-request unique values (request IDs in headers can balloon the dynamic table), and reuse connections so the dynamic table stays warm.