Skip to main content

Dynamic Table

HPACKRFC 7541

The HPACK dynamic table is a per-connection FIFO queue of recently used header name-value pairs. When a client sends a new header like authorization: Bearer token123, HPACK can add it to the dynamic table and reference it by index in future requests. Indexes start at 62 (after the 61 static entries). The table has a maximum size (SETTINGS_HEADER_TABLE_SIZE, default 4096 bytes), and oldest entries are evicted when full.

Details

The dynamic table enables HPACK's key benefit: repeated headers on a connection are compressed to a single integer after the first occurrence.

Connection-specific: Each HTTP/2 connection has two dynamic tables: one for the client's encoder (tracks what the server has seen) and one for the server's encoder (tracks what the client has seen). They are independent.

Table management: Entries are added with literals using incremental indexing (representation type 0x40). Entries are evicted FIFO when the table would exceed its size limit. The size of each entry is header name length + header value length + 32 bytes (overhead constant).

SETTINGS_HEADER_TABLE_SIZE: The server can reduce or disable the dynamic table by sending a SETTINGS frame with SETTINGS_HEADER_TABLE_SIZE=0. Setting it to 0 disables dynamic table indexing entirely. This is sometimes done for privacy (prevents cross-request header correlation).

Dynamic table size update: The encoder can signal a table size reduction in a HEADERS block by including a dynamic table size update (representation starting with 0x20). This allows gradual table size changes without requiring a full SETTINGS round-trip.

Practical impact: For an API that sends the same Authorization header, Content-Type, and Accept headers on every request: First request: headers encoded as literals, added to dynamic table (entries 62, 63, 64) Subsequent requests: headers referenced as indexes 62, 63, 64 = 3 bytes total instead of ~150 bytes

HPACK vs QPACK: HTTP/3 (QUIC) cannot use HPACK because QUIC streams are independent and a dynamic table entry added on stream N may not be visible to stream M (which could arrive out of order). QPACK (RFC 9204) solves this with a separate encoder/decoder stream for table synchronization.

Wire example

HEADERS frame encoding
# First request: authorization header sent as literal, added to dynamic table
# Representation: Literal Header Field with Incremental Indexing
40              # 0x40 = literal with incremental indexing, indexed name to follow
0d              # name length = 13 characters
61 75 74 68 6f 72 69 7a 61 74 69 6f 6e  # "authorization"
22              # value length = 34
42 65 61 72 65 72 20 74 6f 6b 65 6e 31 32 33 ...  # "Bearer token123"
# → Entry 62 added: (authorization, Bearer token123)

# Second request on same connection: 1 byte!
be              # 0xBE = binary 1011 1110 = indexed representation, index 62
# → Full "authorization: Bearer token123" header from 1 byte

See Also