HTTP/2 Server Push & Early Hints
debt(d7/e5/b3/t7)
Closest to 'only careful code review or runtime testing' (d7). No detection_hints.tools are provided for this term. The misuse (pushing already-cached assets, sending 103 after output starts, hinting too many resources) typically surfaces only via careful network inspection (WebPageTest, Chrome DevTools waterfall analysis) or real-user monitoring — not via a linter or static tool. Bandwidth waste from cache-unaware push is silent in normal development.
Closest to 'touches multiple files / significant refactor in one component' (e5). No quick_fix is provided. Fixing cache-aware Server Push requires coordinating server-side push logic with cache headers and potentially CDN configuration. Switching from Server Push to Early Hints, or tuning which resources are hinted, spans server configuration, application middleware, and possibly CDN rules — more than a one-liner but not a full architectural rework.
Closest to 'localised tax' (b3). HTTP/2 push and Early Hints configuration is typically scoped to the server/CDN layer and the set of critical-path resources for a page. It doesn't impose a strong gravitational pull on the rest of the codebase, though it does require ongoing maintenance as resource sets change and cache behaviour must be monitored.
Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception field states explicitly: 'HTTP/2 Server Push is not the same as preload — Push sends the bytes unconditionally; a preload hint lets the browser decide whether to fetch based on its cache.' A competent developer familiar with <link rel=preload> will naturally assume the browser has agency over the fetch, but Server Push bypasses that, wasting bandwidth on already-cached assets. This directly contradicts the mental model of related preload mechanisms.
TL;DR
Explanation
HTTP/2 Server Push allowed servers to send additional resources alongside the initial HTML response, avoiding a round trip for critical assets. In practice it suffered from a fundamental problem: the server cannot know which assets the browser already has cached, leading to wasted bandwidth pushing already-cached resources. Major CDNs (Cloudflare, Chrome) deprecated or removed Server Push support. 103 Early Hints (RFC 8297) is the modern replacement — the server sends a preliminary 103 response with Link: rel=preload headers immediately, while still generating the full page. The browser starts fetching those assets during the server think-time. Unlike Push, the browser controls whether to actually fetch each hint, respecting its own cache. In PHP this is emitted with header('HTTP/1.1 103 Early Hints') before any output.
Watch Out
Common Misconception
Why It Matters
Common Mistakes
- Using Server Push without cache-awareness — pushing already-cached assets wastes bandwidth and can trigger redundant downloads.
- Sending 103 Early Hints after output has started — the 103 must be sent before any body bytes.
- Hinting too many resources — hinting 20 assets defeats the purpose; hint only render-blocking critical resources.
Avoid When
- Avoid HTTP/2 Server Push for new projects — browser support is being removed; use 103 Early Hints or <link rel=preload> instead.
- Do not hint resources that are already in the browser cache for returning users — measure cache hit rates before adding hints.
When To Use
- Send 103 Early Hints for render-blocking CSS and critical fonts on server-rendered pages where DB or API latency is the bottleneck.
- Use Early Hints via CDN (Cloudflare, Fastly) when your origin supports it — the CDN can replay hints from cache without hitting origin.
Code Examples
// Server Push — deprecated, may be ignored or cause duplicate downloads:
header('Link: </style.css>; rel=preload; as=style', false);
// Some servers interpret this as a push directive
// 103 Early Hints — modern, cache-aware:
header('HTTP/1.1 103 Early Hints');
header('Link: </critical.css>; rel=preload; as=style', false);
header('Link: </font.woff2>; rel=preload; as=font; crossorigin', false);
ob_flush(); flush();
// ... expensive DB queries happen here ...
// Browser is already fetching CSS and font in parallel