CDN Cache Invalidation: Strategies for Delivering Fresh Content
CDNs dramatically improve performance by caching content at edge locations worldwide. But caching creates a fundamental challenge: how do you ensure users see updated content when you make changes? Cache invalidation — the process of removing or replacing stale cached content — is one of the hardest problems in web infrastructure.
Why Cache Invalidation Is Hard
Phil Karlton famously said: "There are only two hard things in Computer Science: cache invalidation and naming things." CDN cache invalidation is hard because:
- Distributed state: Content is cached across hundreds of edge nodes globally
- Propagation delay: Invalidation takes time to reach all nodes (seconds to minutes)
- Consistency vs speed: Aggressive caching means faster delivery but staler content
- Cost: Some CDNs charge for purge operations
Cache Invalidation Strategies
1. Purge (Cache Clear)
Explicitly tell the CDN to remove specific URLs from cache:
# Cloudflare API purge
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {token}" \
-d '{"files":["https://example.com/styles.css"]}'
- Pros: Precise, immediate
- Cons: Must know exact URLs, API документацию calls required, propagation delay
2. Cache-Busting (Versioned URLs)
Append a version hash or timestamp to file URLs:
<link rel="stylesheet" href="/css/main.css?v=a1b2c3d4">
<script src="/js/app.js?v=20250315"></script>
/* Or with hashed filenames */
<link rel="stylesheet" href="/css/main.a1b2c3d4.css">
- Pros: No purge needed — new URL = new cache entry. Instant for users.
- Cons: Requires build process to generate hashes, HTML must reference new URLs
3. TTL-Based Expiration
Set appropriate Cache-Control headers so content expires naturally:
# Short TTL for HTML (changes often)
Cache-Control: public, max-age=300
# Long TTL for versioned assets (URL changes on update)
Cache-Control: public, max-age=31536000, immutable
# No cache for dynamic API responses
Cache-Control: no-cache, no-store
4. Stale-While-Revalidate
Serve stale content while fetching fresh content in the background:
Cache-Control: public, max-age=300, stale-while-revalidate=86400
After 5 minutes, the content is "stale" but still served for up to 24 hours while the CDN fetches a fresh copy. Users never see a cache miss delay.
5. Cache Tags (Surrogate Keys)
Tag cached responses with logical identifiers, then purge by tag:
# Response header
Surrogate-Key: product-123 category-electronics homepage
# Purge all content tagged with "product-123"
curl -X POST "https://cdn.example.com/purge/product-123"
This is powerful for CMS-driven sites where one content update affects multiple pages.
Strategy by Content Type
| Content | Strategy | TTL |
|---|---|---|
| HTML pages | Short TTL + purge on publish | 5-60 min |
| CSS/JS (versioned) | Cache-busting + immutable | 1 year |
| Images (versioned) | Cache-busting | 1 year |
| API responses | Short TTL or no-cache | 0-60 sec |
| User-specific | No CDN cache (private) | 0 |
| Fonts | Long TTL + CORS headers | 1 year |
Best Practices
- Version static assets: Cache-busting eliminates the invalidation problem for CSS, JS, and images
- Use stale-while-revalidate: Best of both worlds — fast delivery and eventual consistency
- Automate purges: Trigger CDN purge on deploy or content publish via CI/CD or CMS hooks
- Monitor cache hit rates: Low hit rates mean your TTLs are too short or content is too dynamic
- Test invalidation: Verify purges work before you need them in an emergency
- Layer your caching: CDN edge → origin cache (Varnish/Redis) → application cache
Conclusion
The best cache invalidation strategy is often to avoid invalidation entirely — use versioned URLs for static assets and let cache-busting do the work. For dynamic content, combine short TTLs with stale-while-revalidate. Reserve explicit purges for urgent updates and emergencies.
Check your website right now
Check now →