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, why it failed, and what to use instead.
How it worked
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 intent was to eliminate the “discovery” round-trip: instead of waiting for the browser to parse HTML and then request CSS and JS, the server could start sending those files immediately. In theory this saved one full round-trip of latency for critical resources.
Why it failed
The fatal flaw was that servers had no way to know what the browser already had in its cache. A returning visitor who already had app.css cached would receive a redundant push of the same file, wasting bandwidth and CPU. Servers tended to over-push — sending everything on the page regardless of what the client needed — and the interaction with HTTP/2 stream priority was poorly specified and implemented inconsistently.
Chrome removed server push support in version 106 (September 2022), and HTTP/3 (RFC 9114) never specified push at all. The feature is now effectively deprecated across the web.
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. If a file is already cached, it simply ignores the hint — no wasted bandwidth. The server can send 103 as soon as it starts processing the request, before it finishes generating the HTML, so the critical sub-resource fetches begin at the same time the server is working.
103 Early Hints vs Server Push
| Server Push (deprecated) | 103 Early Hints | |
|---|---|---|
| Browser cache awareness | None — always sends bytes | Client checks cache before fetching |
| Client control | RST_STREAM to cancel | Normal cache logic |
| HTTP/3 support | No | Yes |
| Implementation complexity | High (server manages streams) | Low (add a response header) |
| Browser support | Removed | Chrome, Edge, Firefox, Cloudflare |
This is the recommended path on HTTP/2 and HTTP/3. Most CDNs and frameworks support 103 Early Hints via response headers rather than requiring HTTP/2-level plumbing.