Featured image of post CDN Caching Strategies: Maximize Performance and Freshness Featured image of post CDN Caching Strategies: Maximize Performance and Freshness

CDN Caching Strategies: Maximize Performance and Freshness

Comprehensive guide to CDN caching strategies covering cache-control directives, surrogate keys, invalidation, stale-while-revalidate, purging, and origin shield.

Introduction

Content Delivery Networks (CDNs) are the backbone of modern web performance. By caching content at edge nodes distributed globally, CDNs dramatically reduce latency and offload traffic from origin servers. However, effective caching is not simply a matter of enabling a CDN and forgetting about it. Striking the right balance between performance — high cache hit rates and low latency — and freshness — minimal staleness and fast invalidation — requires deliberate strategy.

This guide explores CDN caching fundamentals, Cache-Control directives, surrogate keys, invalidation strategies, stale-while-revalidate, multi-layer caching, and monitoring, providing practical recipes you can apply today.


CDN Caching Fundamentals

CDN caching stores copies of responses at edge nodes (Points of Presence, or POPs) so subsequent requests for the same resource can be served without contacting the origin server. On a cache hit, responses are served in 5–50 milliseconds. On a cache miss, the request travels to the origin, adding 100–500 milliseconds of latency.

CDNs cache a wide range of content: static assets (images, CSS, JavaScript, fonts), API responses (JSON, GraphQL), HTML pages, and streaming content. The cache hierarchy typically follows edge nodes → regional caches → origin shield → origin server.

Different CDN providers have different caching philosophies and capabilities:

ProviderCache-ControlSurrogate KeysOrigin ShieldSWR Support
CloudflareFullCache-TagArgo Tiered CacheYes
FastlyFullSurrogate-KeyFastly ShieldYes
AkamaiFullCache-TagProperty ManagerYes
CloudFrontFullOrigin ShieldYes

Cache-Control Directives in Depth

The Cache-Control header is the primary mechanism for instructing CDNs and browsers how to cache responses. Understanding its directives is essential for fine-tuning behavior.

  • max-age=<seconds> — Specifies how long a resource remains fresh. For versioned assets like app.a1b2c3.js, set max-age=31536000 with the immutable directive.
  • s-maxage=<seconds> — Overrides max-age specifically for shared caches (CDNs and proxies), letting you set different TTLs for CDNs versus browsers.
  • public vs privatepublic allows caching by CDNs and browsers; private restricts caching to the browser only, which is important for user-specific content.
  • no-cache vs no-storeno-cache permits caching but requires revalidation on every request. no-store outright forbids caching.
  • stale-while-revalidate=<seconds> — Serves stale content immediately while fetching fresh content in the background.
  • immutable — Tells browsers the resource will never change during its freshness lifetime, eliminating conditional revalidation.

Here is a practical recipe for different content types:

# Versioned static asset — cache for a year, skip revalidation
Cache-Control: public, max-age=31536000, immutable

# API response — fresh for 1 minute, stale for 24 hours
Cache-Control: public, s-maxage=60, stale-while-revalidate=86400

# HTML page — always revalidate
Cache-Control: public, no-cache

Surrogate Keys and Targeted Invalidation

Surrogate keys (also called origin cache tags) allow you to group related resources for targeted cache invalidation. Instead of purging individual URLs, you purge by tag — a far more efficient approach for grouped content.

Implementation is straightforward: your origin server includes a Surrogate-Key header (Fastly) or Cache-Tag header (Cloudflare, Akamai) in responses. Tags can represent content type (articles), specific entities (article:1234), collections (section:tech), or actions (purge-all).

# Response header tagging an article
Cache-Tag: articles, article:1234, section:tech

When an article is updated, purge all cached responses tagged with that ID:

# Fastly surrogate key purge
curl -X POST "https://api.fastly.com/service/{service}/purge/article:1234" \
  -H "Fastly-Key: $API_KEY"

# Cloudflare tag purge
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone}/purge_cache" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tags":["article:1234"]}'

Best practices for tag naming: avoid whitespace, keep casing consistent, and limit tags to fewer than 256 per response to stay within provider limits.


Stale-While-Revalidate

Stale-While-Revalidate (SWR) is a Cache-Control extension that transforms the cache-miss penalty from a synchronous wait into a background refresh. When a request arrives for a stale resource, the CDN serves the stale version immediately while fetching the fresh version asynchronously.

Cache-Control: public, max-age=60, stale-while-revalidate=86400

This keeps the resource fresh for 60 seconds and allows serving stale content for up to 24 hours while revalidating in the background. Users see zero waiting time — they always get an instant response. SWR pairs well with stale-if-error, which serves stale content as a fallback when the origin is unreachable. Monitor the stale-to-fresh ratio in your CDN dashboard to tune the SWR window appropriately.


Multi-Layer Caching and Origin Shield

Effective caching operates on multiple layers:

  1. Browser cache — The first line of defense. Proper Cache-Control headers prevent repeat requests.
  2. CDN edge cache — Distributed edge nodes serving cached content to nearby users.
  3. CDN origin shield — An intermediate cache that consolidates requests from edge nodes, dramatically reducing origin load.
  4. Application cache — Redis or Memcached at the origin for database results and rendered fragments.
  5. Database query cache — Caching frequent query results at the database level.

Origin shield deserves special attention. When multiple edge nodes miss cache for the same asset, they each contact the origin — a thundering herd problem. The origin shield intercepts these requests, checks its own cache, and only contacts the origin once. This reduces origin traffic by 80–95%. Configure it via Cloudflare Argo Tiered Cache, Fastly Shield, or CloudFront Origin Shield.


Monitoring and Debugging

To ensure your caching strategy is working, monitor these metrics:

  • Cache hit ratio — Available in Cloudflare Analytics, Fastly Observatory, and CloudFront Reports. Above 80% is good; above 95% is excellent.
  • CDN response headersCF-Cache-Status (Cloudflare), X-Cache (Fastly, CloudFront), and Age tell you whether a response was served from cache and how long it has been cached.
  • Cache miss analysis — Identify why an asset missed: first request, eviction, TTL expiry, or explicit bypass.

Use curl to debug caching headers:

curl -I https://example.com/assets/app.js -H "Accept-Encoding: gzip"
# Look for: CF-Cache-Status: HIT, Age: 12345

Conclusion

Effective CDN caching combines appropriate TTLs, surrogate keys for targeted invalidation, stale-while-revalidate for zero-wait refreshes, and multi-layer caching with origin shield for resilience. The single most impactful directive is stale-while-revalidate — it transforms the performance-freshness trade-off from a compromise into a both/and proposition. Pair it with a well-designed surrogate key system, invest in origin shield, and monitor your cache hit ratios to continuously improve. Your users will thank you with faster load times, and your origin servers will thank you with reduced load.