Complete Guide to Image Caching Strategies - Cache-Control, ETag, and CDN Configuration
Web Image Caching Basics - Browser Cache and CDN Cache Roles
Image caching is fundamental to web performance. Proper caching strategies prevent image re-downloads and dramatically reduce page load times. Caching operates in two main layers.
Browser cache (client-side): Stores images on the user's device, completely eliminating re-requests for the same image. Controlled by the Cache-Control HTTP response header, cache hits require no network requests, making display speed effectively zero seconds.
CDN cache (edge servers): Caches images on edge servers positioned in front of origin servers. Even without browser cache, serving from geographically nearby edge servers reduces latency. CloudFront, Cloudflare, and Fastly are representative CDNs.
Caching effectiveness: According to HTTP Archive research, proper cache configuration serves 60-80% of image requests from cache. This directly reduces bandwidth costs and server load. Since images account for approximately 50% of web page transfer volume, they are the resource type where caching has the greatest impact.
Cache strategy design requires balancing "cache freshness" with "cache invalidation." Overly long caches risk displaying stale images, while overly short caches lose performance benefits.
Cache-Control Header Design - Combining Directives
Cache-Control is the most important header controlling HTTP cache behavior. Combine appropriate directives based on image type and update frequency.
Immutable static images (hashed filenames):
Cache-Control: public, max-age=31536000, immutable
Images with content hashes in filenames (e.g., hero-a1b2c3d4.jpg) can safely be cached for 1 year (31536000 seconds) since content changes mean filename changes. The immutable directive indicates browsers should not even perform cache revalidation (conditional requests).
Potentially updatable images:
Cache-Control: public, max-age=86400, must-revalidate
For user-uploaded or profile images where content may change at the same URL, set shorter max-age (1 day = 86400 seconds) with must-revalidate. After cache expiry, revalidation with the server is mandatory.
Cache prohibition:
Cache-Control: no-store
Images containing personal information (identity documents, etc.) must not be cached. no-store completely prohibits caching in both browsers and intermediate caches.
stale-while-revalidate:
Cache-Control: public, max-age=3600, stale-while-revalidate=86400
Returns stale cache immediately after expiry while revalidating in the background. Users always receive instant responses, improving perceived speed.
ETag and Conditional Requests - Efficient Cache Revalidation
ETag (Entity Tag) is a string identifying a specific version of a resource. It efficiently determines whether a resource has actually changed after cache expiry.
ETag operation flow:
- Initial request: Server includes
ETag: "abc123"in response - Re-request (after cache expiry): Browser sends
If-None-Match: "abc123"header - No change: Server returns
304 Not Modified(no body, few hundred bytes) - Changed: Server returns
200 OKwith new image data
Since 304 Not Modified responses contain no body, image data retransmission is avoided. Even for a 1MB image, if unchanged, a few hundred bytes suffice for the 304 response.
ETag generation methods:
- Strong ETag: Generated from file content hash (MD5, SHA-256, etc.). Guarantees byte-level identity
- Weak ETag:
W/"abc123"format. Indicates semantic equivalence (e.g., different compression but same content)
Comparison with Last-Modified: Last-Modified can also be used for conditional requests (If-Modified-Since), but has only second-level precision and depends on filesystem timestamps, making it less reliable. ETag provides content-based verification and is more accurate. ETag usage is recommended in CDN environments.
Caution: With multiple origin servers, ensure the same file doesn't generate different ETags. Inode-based ETags (Apache default) differ per server, so switch to content-hash-based generation.
CDN Cache Design - CloudFront and Cloudflare Configuration Examples
CDN cache configuration can either respect the origin server's Cache-Control headers or set independent cache policies on the CDN side.
CloudFront configuration:
- Cache policy: Managed policy
CachingOptimizedcaches based onCache-ControlandExpiresheaders. Default TTL is 86400 seconds (1 day) - Custom policy: Create an image-specific cache policy with minimum TTL of 86400 and maximum TTL of 31536000. Control whether query strings are included in cache keys
- Origin request policy: Configure to forward
Acceptheader to origin when enabling WebP/AVIF Content Negotiation
Cloudflare configuration:
- Browser Cache TTL: Set in Cloudflare dashboard. Selecting "Respect Existing Headers" uses origin's
Cache-Controlas-is - Edge Cache TTL: Set per URL pattern via Page Rules. Common to set Edge Cache TTL to 1 month for
/images/* - Polish: Automatic image optimization feature. Performs WebP conversion and lossless compression at CDN edge
Cache key design: CDN cache keys should include the Accept header used for image format negotiation in addition to URL path. This enables serving WebP from cache to supported browsers and JPEG to unsupported ones at the same URL. Achieved by including Accept in the Vary header.
Cache Invalidation Strategies - Ensuring Image Updates Are Reflected
The biggest caching challenge is "how to reliably invalidate stale caches." Even after updating images, old versions remaining in user browsers or CDN prevent updates from appearing.
Strategy 1: Filename versioning with content hashes
The most reliable method. Include content hash in image filenames:
hero-image-a1b2c3d4e5f6.jpg
When images update, the hash changes creating a new URL, completely eliminating stale cache issues. HTML references must also update simultaneously, requiring build pipeline integration. Automate with Webpack's [contenthash] or Vite's asset hashing.
Strategy 2: Query string versioning
hero-image.jpg?v=20250723
Manages versions via query strings without changing filenames. Simple to implement, but some CDNs and proxies may ignore query strings when caching, making it less reliable than hash-based approaches.
Strategy 3: CDN cache purge (Invalidation)
Forcibly deletes CDN edge caches. Execute via CloudFront's CreateInvalidation API or Cloudflare's Purge Cache API. Takes effect immediately, but propagation to all edge locations may take several minutes.
Recommended approach: Use content-hash filename versioning as the foundation, with CDN purge only for emergencies. For user-uploaded images with fixed URLs, use short max-age + ETag combination.
Advanced Cache Control with Service Workers - Offline Support and Strategic Caching
Service Workers enable advanced caching strategies beyond standard browser cache mechanisms. They allow offline image support and adaptive delivery based on network conditions.
Cache First strategy (optimal for images):
self.addEventListener("fetch", (event) => { if (event.request.destination === "image") { event.respondWith( caches.match(event.request).then((cached) => { return cached || fetch(event.request).then((response) => { const cache = await caches.open("images-v1"); cache.put(event.request, response.clone()); return response; }); }) ); }});
This strategy returns immediately from cache on hit, only making network requests on miss. Cache First is optimal for images since they rarely change.
Stale While Revalidate strategy: Returns from cache immediately while fetching the latest version in the background to update the cache. The next access shows the updated version. Suitable for moderately-updated images like profile pictures.
Cache size management: Service Worker cache storage has capacity limits (varies by browser, typically 50MB to several hundred MB). Implement LRU (Least Recently Used) auto-deletion logic for old entries. Workbox library's ExpirationPlugin easily configures maximum entry count and retention period.
Responsive image caching: When serving multiple sizes via srcset, Service Workers can cache only the optimal size for the device's screen width, reducing storage usage. Avoid caching unnecessary high-resolution images and retain only device-appropriate sizes.