What HTTP/2 frames are
HTTP/2 replaces the text protocol of HTTP/1.1 with a binary framing layer. Every exchange is a stream of typed frames multiplexed over one TCP connection. Each frame begins with a fixed 9-byte header — a 24-bit length, an 8-bit type, an 8-bit flags field and a 31-bit stream identifier — followed by a type-specific payload. This reference lists all ten frame types from RFC 9113 with their type code, flags and scope.
Frame type quick-reference
| Type code | Name | Connection / Stream | Purpose |
|---|---|---|---|
| 0x0 | DATA | Stream | Carries request or response body bytes |
| 0x1 | HEADERS | Stream | Header block fragment; opens a new stream |
| 0x2 | PRIORITY | Stream | Stream dependency and weight (deprecated in RFC 9218) |
| 0x3 | RST_STREAM | Stream | Abruptly terminates a stream |
| 0x4 | SETTINGS | Connection | Exchange configuration parameters |
| 0x5 | PUSH_PROMISE | Stream | Reserve a stream for a server-initiated push |
| 0x6 | PING | Connection | Round-trip latency measurement / keepalive |
| 0x7 | GOAWAY | Connection | Graceful shutdown; last processed stream id |
| 0x8 | WINDOW_UPDATE | Both | Flow control credit for connection or stream |
| 0x9 | CONTINUATION | Stream | Overflow for a header block too large for one HEADERS frame |
How it works
The frame header tells the receiver how to interpret the payload:
+-----------------------------------------------+
| Length (24) |
+---------------+---------------+---------------+
| Type (8) | Flags (8) |
+-+-------------+---------------+-------------------------------+
|R| Stream Identifier (31) |
+=+=============================================================+
| Frame Payload (length octets) ...
+---------------------------------------------------------------+
Stream id 0 means the frame applies to the whole connection (SETTINGS, PING,
GOAWAY). A non-zero id ties the frame to a single request/response stream. Flags
like END_STREAM and END_HEADERS mark boundaries; ACK acknowledges SETTINGS
and PING.
Key flags to know
| Flag | Hex | Used on | Meaning |
|---|---|---|---|
END_STREAM | 0x1 | DATA, HEADERS | No more frames from this sender on this stream |
END_HEADERS | 0x4 | HEADERS, CONTINUATION, PUSH_PROMISE | Header block is complete |
PADDED | 0x8 | DATA, HEADERS, PUSH_PROMISE | Padding bytes appended to hide payload length |
PRIORITY | 0x20 | HEADERS | Carries dependency and weight (legacy) |
ACK | 0x1 | SETTINGS, PING | Acknowledgement |
The request/response lifecycle in frames
A typical GET request over HTTP/2 looks like this at the frame level:
- Client sends
HEADERS(stream 1,END_HEADERS+END_STREAM) — request headers, no body. - Server sends
HEADERS(stream 1,END_HEADERS) — response status and headers. - Server sends
DATA(stream 1,END_STREAM) — response body.
A POST with a request body adds a DATA frame from the client between steps 1 and 2, with END_STREAM on the last body frame. All streams are multiplexed over the same TCP connection without head-of-line blocking (unlike HTTP/1.1 pipelining).
Tips
- A new request is a HEADERS frame (optionally with CONTINUATION) opening a fresh, odd-numbered, client-initiated stream id. Server-pushed streams use even ids.
- SETTINGS must be ACKed; never assume a setting is active until the peer’s ACK arrives. The initial SETTINGS exchange happens immediately after the connection preface.
- WINDOW_UPDATE drives flow control — a stalled stream almost always means the sender is waiting for a flow-control credit from the receiver.
- GOAWAY carries the last processed stream id so the client knows which requests to safely retry on a new connection.