HTTP/2 Server Push vs Preload: Why Push Failed at Scale
The Promise of Server Push
HTTP/2 introduced Server Push to allow servers to proactively send resources before the client requests them. The concept was compelling: after the server sends the HTML document, it could immediately push the referenced CSS and JavaScript files, saving one RTT (round-trip time) per resource on a cold cache (when the browser has no cached copy). Instead of the browser parsing HTML, discovering it needs style.css, and then requesting it, the server would push style.css alongside the HTML. For a page referencing 5 critical resources, this could theoretically save 400ms on an 80ms RTT connection.
The Cache Coordination Problem
Production deployments revealed a fundamental problem: the server cannot reliably know what the client has cached. If the server pushes a 200KB JavaScript bundle that the browser already has cached, it wastes bandwidth and potentially evicts other cached resources. This cache coordination problem proved intractable at scale. Without complex state synchronization between client and server (which would add latency and complexity defeating the purpose), the server must guess. Guessing wrong wastes bandwidth, and on mobile connections with metered data or slow speeds, this waste directly harms user experience. Empirical measurements found that naive push strategies often pushed assets already cached 60-80% of the time on returning visitors.
Prioritization Conflicts
Server Push also complicates resource prioritization. Pushed resources compete for bandwidth with the HTML document itself. If the server pushes large JavaScript bundles while still sending HTML, it can delay first byte of critical inline content, degrading FCP (First Contentful Paint, when the browser first renders something visible). The browser's resource scheduler is carefully tuned to prioritize critical rendering path resources; push bypasses this intelligence. Measurements found push strategies frequently degraded page load time by 5-10% in the median case and up to 20% in worst cases when pushing large bundles already cached.
Modern Alternatives
Modern best practice has converged on client-driven alternatives that preserve cache awareness. HTTP 103 Early Hints allows servers to send Link preload headers before the full HTML response is ready. The server sends a 103 response with hints like Link: </style.css>; rel=preload, and the browser initiates fetches while waiting for the 200 response. The browser retains full cache awareness: if style.css is cached, it simply skips the fetch. This achieves equivalent RTT savings without push's downsides. Resource preload directives in HTML (<link rel=preload>) serve similar purposes for resources discovered during HTML parsing.
Industry Outcome
Major platforms have largely disabled or severely limited Server Push in favor of client-driven alternatives. The HTTP/3 specification deprioritized push semantics accordingly, effectively acknowledging the feature's failure in practice. At scale, the bandwidth waste is substantial: at 10 million requests per hour, pushing 100KB assets already cached 70% of the time wastes approximately 700GB of egress bandwidth, translating to significant infrastructure costs. The lesson: features that seem theoretically beneficial can fail when real-world complexity (caching, prioritization, network variability) is considered.