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=43200for CDN resilience during origin downtimeETag+Last-Modifieddual 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.