Cache-Control Headers for Image and Video Assets

Proper Cache-Control configuration dictates how browsers, CDNs, and intermediate proxies store media. Aligning cache directives with immutable asset fingerprints reduces origin load by 30–60%. For granular tuning strategies, see Best practices for setting max-age on CDN media assets.

Implementation Patterns & Server Configuration

Directives like max-age, public, immutable, and stale-while-revalidate must be applied contextually. Static fingerprinted assets should use long-lived caching to bypass validation entirely. For frequently updated assets, stale-while-revalidate ensures immediate delivery while background updates occur.

location ~* \.(jpg|jpeg|png|webp|avif|mp4|webm)$ {
  expires 1y;
  add_header Cache-Control "public, max-age=31536000, immutable";
  # Vary on Accept-Encoding only; add Vary: Accept separately for format-negotiated assets
  add_header Vary "Accept-Encoding";
}

The following JSON structure works for Vercel, Netlify, and similar static hosts that accept a headers config file:

{
  "headers": [
    {
      "source": "/assets/media/(.*)",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "public, max-age=31536000, immutable"
        }
      ]
    }
  ]
}

Browser Quirk: Safari historically requires an explicit max-age value alongside immutable; the directive alone is not sufficient. Always pair Vary: Accept-Encoding when serving compressed assets to prevent Brotli-encoded responses reaching clients that don’t support it.

Format-Specific Caching & Browser Support Matrix

Format Browser Support Cache Directive Notes
AVIF Chrome 85+, Safari 16+, Firefox 93+ public, max-age=31536000, immutable High compression; ideal for static hero images
WebP Chrome 23+, Safari 14+, Firefox 65+ public, max-age=31536000, immutable Balanced fallback; supports animation/transparency
MP4 (H.264) Universal public, max-age=604800, stale-while-revalidate=43200 Legacy baseline; suitable for frequently updated editorial video
WebM (VP9) Chrome 32+, Firefox 31+, Safari 14+ public, max-age=604800, immutable Optimal for transparent video overlays

Note: WebP is as cacheable as AVIF for versioned assets — there is no reason to use a shorter max-age for WebP unless your pipeline generates non-fingerprinted URLs.

Adaptive Bitrate Streaming & Chunk-Level Caching

HLS and DASH manifests should use short-lived max-age values with stale-while-revalidate to accommodate live playlist updates. Media segments (.ts, .m4s) benefit from immutable caching once encoded. Proper segment caching reduces rebuffering events and optimizes CDN edge storage. For codec-level context, see Understanding Video Codecs: VP9 vs H.265 vs AV1.

Component Cache Strategy Rationale
Manifests (.m3u8, .mpd) public, max-age=60, stale-while-revalidate=120 Enables rapid playlist updates without full cache invalidation
Segments (.ts, .m4s) public, max-age=31536000, immutable Eliminates validation overhead for static chunks
CDN Enable range request caching Supports byte-range serving for large video files

Browser Quirk: Chrome’s Media Source Extensions (MSE) prefetches segments aggressively. Ensure Accept-Ranges: bytes is explicitly set in origin responses to prevent 206 Partial Content failures at edge nodes.

Fallback Strategies & Cache Miss Handling

When edge nodes purge assets unexpectedly, graceful degradation prevents layout shifts. stale-if-error=43200 serves expired assets during origin outages.

  • stale-if-error=43200 for CDN resilience during origin downtime
  • ETag + Last-Modified dual validation for precise origin synchronization
  • Client-side service worker cache-first with network fallback for PWA media delivery

Browser Quirk: Firefox ignores stale-if-error on cross-origin requests without explicit CORS headers. Always include Access-Control-Expose-Headers: Cache-Control for cross-origin media endpoints.

Core Web Vitals & Accessibility Impact

Long-lived caching of above-the-fold media improves LCP by 20–40% on repeat visits. Correct immutable flags reduce CLS by preventing delayed asset swaps.

Metric Impact Measurement
LCP Improvement 20–40% on repeat visits Edge cache hit ratio >95%
CLS Mitigation Eliminates layout thrashing from late-loading swaps Zero fallback swaps post-initial-load
Bandwidth Conservation 30–60% origin egress reduction CDN transfer volume logs

Always validate layout stability using Chrome DevTools Performance panel with network throttling enabled, not just local testing where iOS Safari’s aggressive memory cache can mask CLS issues.