HTTP/2 Server Push Issues | Blue Frog Docs

HTTP/2 Server Push Issues

Diagnose and fix HTTP/2 Server Push implementation problems and over-pushing issues

HTTP/2 Server Push Issues

What This Means

HTTP/2 Server Push allows servers to send resources to the browser before they're requested, potentially improving page load times. However, incorrect implementation can actually harm performance by pushing resources the browser already has cached or doesn't need.

How Server Push Works

Normal Process:

  1. Browser requests HTML
  2. Server sends HTML
  3. Browser parses HTML
  4. Browser requests CSS, JS, images
  5. Server sends resources

With Server Push:

  1. Browser requests HTML
  2. Server sends HTML + pushes CSS, JS immediately
  3. Browser receives resources before parsing HTML
  4. Faster rendering (when done correctly)

Important Note About Server Push in 2025

Chrome has removed support for HTTP/2 Server Push as of version 106 (2022). Other browsers are following suit.

Why It's Being Deprecated:

  • High complexity, low adoption
  • Easy to misconfigure and harm performance
  • Better alternatives exist (preload, early hints)
  • Caching issues difficult to solve

Modern Alternatives:

  • <link rel="preload"> - Better browser support
  • 103 Early Hints - New standard, better design
  • HTTP/3 doesn't include server push
  • Resource prioritization via Priority Hints

Impact on Your Business

When Misconfigured:

  • Wasted bandwidth from pushing cached resources
  • Slower page loads from over-pushing
  • Increased server load
  • Cache invalidation problems

Modern Best Practice:

  • Remove server push configurations
  • Use preload links instead
  • Implement 103 Early Hints where available
  • Focus on resource prioritization

Common Causes

Over-Pushing Resources

# Wrong: Pushing too many resources
Link: </css/style.css>; rel=preload; as=style
Link: </js/script1.js>; rel=preload; as=script
Link: </js/script2.js>; rel=preload; as=script
Link: </js/script3.js>; rel=preload; as=script
Link: </images/hero.jpg>; rel=preload; as=image
Link: </images/logo.png>; rel=preload; as=image
Link: </fonts/font.woff2>; rel=preload; as=font
# Result: Bandwidth waste, slow connection saturation

Pushing Cached Resources

# Wrong: No cache-awareness
location / {
    http2_push /css/style.css;
    http2_push /js/app.js;
}
# Problem: Pushes even if browser has cached versions

Pushing Wrong Resources

# Wrong: Pushing non-critical resources
Link: </analytics.js>; rel=preload; as=script
Link: </ads.js>; rel=preload; as=script
# Problem: Delays critical resource delivery

Push Without HTTP/2

# Configuration exists but HTTP/2 not enabled
http2_push /style.css;
# No effect without HTTP/2

How to Diagnose

Method 1: Chrome DevTools Network Tab

Note: Server Push removed in Chrome 106+, but you can check headers:

  1. Open DevTools (F12)
  2. Go to Network tab
  3. Reload page
  4. Click on HTML document
  5. Check Response Headers for Link: headers with rel=preload

What to Look For:

Link: </css/style.css>; rel=preload; as=style
Link: </js/app.js>; rel=preload; as=script

Method 2: Check HTTP/2 Status

  1. Open DevTools Network tab
  2. Right-click column headers
  3. Enable "Protocol" column
  4. Look for "h2" (HTTP/2) or "h3" (HTTP/3)

What to Look For:

  • Protocol: h2 (HTTP/2 enabled)
  • Protocol: http/1.1 (HTTP/2 not enabled)
  • Protocol: h3 (HTTP/3, no push support)

Method 3: WebPageTest

  1. Visit WebPageTest.org
  2. Enter your URL
  3. Run test
  4. Check "Connection View"
  5. Look for pushed resources

What to Look For:

  • Resources marked as "PUSH_PROMISE"
  • Pushed resources vs. requested resources
  • Push timing and efficiency

Method 4: Command Line Testing

# Check for HTTP/2 support
curl -I --http2 https://example.com

# Look for:
HTTP/2 200

# Check for Link headers
curl -I https://example.com | grep -i "link:"

Method 5: Server Configuration Check

Apache:

# Check if mod_http2 is enabled
apache2ctl -M | grep http2

# Check configuration
grep -r "H2Push" /etc/apache2/

Nginx:

# Check nginx version (1.13.9+ for push)
nginx -v

# Check configuration
grep -r "http2_push" /etc/nginx/

General Fixes

Replace server push with <link rel="preload">:

<!-- In HTML <head> -->
<link rel="preload" href="/css/critical.css" as="style">
<link rel="preload" href="/js/app.js" as="script">
<link rel="preload" href="/fonts/font.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/images/hero.jpg" as="image">

<!-- Then load normally -->
<link rel="stylesheet" href="/css/critical.css">
<script src="/js/app.js" defer></script>

Benefits:

  • Better browser support
  • Browser handles caching properly
  • Easier to implement
  • More granular control

Fix 2: Implement 103 Early Hints

Modern alternative to server push:

Server sends 103 response immediately:

HTTP/1.1 103 Early Hints
Link: </style.css>; rel=preload; as=style
Link: </script.js>; rel=preload; as=script

HTTP/1.1 200 OK
Content-Type: text/html
...

Cloudflare Example:

// Cloudflare Worker
export default {
  async fetch(request) {
    const response = await fetch(request);

    // Send Early Hints
    return new Response(response.body, {
      status: response.status,
      headers: {
        ...response.headers,
        'Link': '</css/style.css>; rel=preload; as=style, </js/app.js>; rel=preload; as=script'
      }
    });
  }
}

Fix 3: Remove Server Push Configuration

Apache (.htaccess or httpd.conf):

# Remove these directives:
# H2Push Off
# H2PushResource add /css/style.css
# H2PushPriority * after

# Or explicitly disable:
H2Push Off

Nginx (nginx.conf):

# Remove these directives:
# http2_push /css/style.css;
# http2_push /js/app.js;

# Comment them out:
# location / {
#     http2_push /css/style.css;
# }

Node.js (Express):

// Remove server push code
// const http2 = require('http2');
// stream.pushStream({ ':path': '/css/style.css' }, ...);

// Use Link headers for preload instead
app.use((req, res, next) => {
  res.setHeader('Link', '</css/style.css>; rel=preload; as=style');
  next();
});

Fix 4: Optimize Preload Strategy

Only preload critical resources:

<!-- Good: Preload only critical above-fold resources -->
<head>
  <!-- Critical CSS -->
  <link rel="preload" href="/css/critical.css" as="style">

  <!-- Critical font -->
  <link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

  <!-- LCP image -->
  <link rel="preload" href="/images/hero.jpg" as="image" fetchpriority="high">

  <!-- Critical JavaScript -->
  <link rel="preload" href="/js/app.js" as="script">
</head>
<!-- Bad: Preloading everything -->
<head>
  <link rel="preload" href="/css/style.css" as="style">
  <link rel="preload" href="/css/responsive.css" as="style">
  <link rel="preload" href="/css/print.css" as="style">
  <link rel="preload" href="/js/analytics.js" as="script">
  <link rel="preload" href="/js/ads.js" as="script">
  <!-- Too many preloads harm performance -->
</head>

Fix 5: Use Resource Hints Properly

Combine preload with other hints:

<!-- DNS prefetch for third-party domains -->
<link rel="dns-prefetch" href="https://analytics.google.com">

<!-- Preconnect for critical third-party resources -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<!-- Preload critical resources -->
<link rel="preload" href="/css/critical.css" as="style">

<!-- Prefetch for next page navigation -->
<link rel="prefetch" href="/next-page.html">

Fix 6: Implement Priority Hints

Use fetchpriority for better control:

<!-- High priority: LCP image -->
<img src="hero.jpg" fetchpriority="high" alt="Hero">

<!-- Low priority: Below-fold image -->
<img src="footer-logo.png" fetchpriority="low" loading="lazy" alt="Logo">

<!-- High priority: Critical CSS -->
<link rel="preload" href="/critical.css" as="style" fetchpriority="high">

<!-- Low priority: Analytics -->
<script src="/analytics.js" fetchpriority="low" async></script>

Fix 7: Configure CDN-Level Optimizations

Cloudflare:

  • Enable "Early Hints" in Speed settings
  • Configure custom cache rules
  • Use Workers for dynamic hints

Other CDNs:

  • Check for Early Hints support
  • Configure edge caching properly
  • Review resource prioritization options

Platform-Specific Guides

Detailed implementation instructions for your specific platform:

Platform Troubleshooting Guide
Apache Apache Preload Configuration
Nginx Nginx Resource Hints
Cloudflare Cloudflare Early Hints
WordPress WordPress Resource Hints
Node.js Node.js Preload Setup

Testing & Validation

After implementing fixes:

Step 1: Verify Preload Headers

# Check for Link headers
curl -I https://example.com

# Look for:
Link: </css/style.css>; rel=preload; as=style

Step 2: Chrome DevTools Network Tab

  1. Open DevTools (F12)
  2. Go to Network tab
  3. Enable "Priority" column
  4. Reload page
  5. Verify:
    • Preloaded resources load early
    • Correct priorities (High, Low, etc.)
    • No duplicate requests

Step 3: PageSpeed Insights

  1. Run test on PageSpeed Insights
  2. Check for warnings:
    • "Preload key requests" - should pass if implemented
    • No warnings about render-blocking
  3. Verify improved FCP and LCP

Step 4: WebPageTest

  1. Run test on WebPageTest
  2. Check waterfall chart
  3. Verify preloaded resources start early
  4. Check for connection efficiency

Step 5: Lighthouse Audit

  1. Open DevTools
  2. Go to Lighthouse tab
  3. Run Performance audit
  4. Check:
    • "Preload key requests" passes
    • "Uses passive listeners" passes
    • Overall performance score improved

Common Mistakes

  1. Keeping old server push config - Remove deprecated configurations
  2. Preloading too many resources - Limit to 3-5 critical resources
  3. Preloading without using - Every preload must be used on the page
  4. Wrong as= attribute - Must match resource type
  5. Forgetting crossorigin for fonts - Required for CORS
  6. Not testing on slow connections - Over-preloading hurts slow connections
  7. Preloading third-party resources - Only preload same-origin or CORS-enabled
  8. Missing fetchpriority - Not utilizing modern priority hints

Migration Checklist

Moving from Server Push to modern alternatives:

  1. Audit Current Setup

    • Document all pushed resources
    • Identify critical vs. non-critical resources
    • Check browser support requirements
  2. Implementation

    • Remove server push configuration
    • Add preload links for critical resources
    • Implement priority hints
    • Configure 103 Early Hints (if CDN supports)
  3. Testing

    • Test with Chrome DevTools
    • Run PageSpeed Insights
    • Test on slow connections
    • Verify performance metrics improved
  4. Monitoring

    • Monitor Core Web Vitals
    • Track LCP and FCP metrics
    • Watch for regressions
    • Adjust preload strategy as needed

Further Reading

// SYS.FOOTER