HTTP/2 Server Push let a server send resources to a client before they were requested, using a
PUSH_PROMISE frame. In practice it under-delivered and is now removed from browsers. This
reference documents how it worked and what to use instead.
How it works
A pushed resource follows this lifecycle on an HTTP/2 connection:
- The server sends a
PUSH_PROMISEframe on the client’s request stream, reserving a new server-initiated (even-numbered) stream ID and carrying the promised request header block. - The server then sends
HEADERS+DATAfor that pushed response on the reserved stream. - The client may accept it, or send
RST_STREAMwithCANCEL/REFUSED_STREAMto decline — useful when the resource is already in cache. - A client can disable push for the whole connection with
SETTINGS_ENABLE_PUSH = 0.
The fatal flaw: servers routinely pushed resources the browser had already cached, wasting bandwidth, and push interacted badly with prioritization. Chrome removed it in v106 (2022), and HTTP/3 never specified push at all.
The modern replacement — 103 Early Hints
Instead of pushing bytes, the server sends an informational 103 Early Hints response carrying
Link headers with rel=preload while it prepares the real response:
HTTP/2 103 Early Hints
Link: </app.css>; rel=preload; as=style
Link: </app.js>; rel=preload; as=script
HTTP/2 200 OK
Content-Type: text/html
...
The browser starts fetching the hinted resources immediately but stays in control of caching, so it never re-downloads something it already has. This is the recommended path on HTTP/2 and HTTP/3.