CDN Caching Strategies
CDN caching strategies represent the intersection of two critical concepts we’ve explored: the fundamental caching principles from Chapter 6 and the geographic distribution infrastructure of Chapter 7. While local caches optimize for latency within a single location, CDN caches must balance freshness, origin load, and geographic scale across thousands of edge servers worldwide. The decisions you make about what to cache, for how long, and how to invalidate that cache directly impact both user experience and your infrastructure costs.
This chapter guides you through the practical art of configuring CDNs to serve cached content intelligently. You’ll learn how HTTP headers tell edge servers whether to cache, when to revalidate, and how to update content without waiting for TTL expiration. These strategies aren’t one-size-fits-all—a product image can safely live in edge caches for months, while checkout information must never be cached, and a real-time stock price might be cached for just five seconds.
How CDN Caches Decide: The Fundamentals
CDNs make caching decisions based on HTTP headers, request characteristics, and configured rules. The primary decision-making mechanism is the Cache-Control header, which the origin server uses to communicate caching intent. Unlike traditional reverse proxy caches, CDN edge servers operate at the boundary between your origin and users worldwide, making their caching logic more nuanced.
Time-to-Live (TTL) strategies form the backbone of CDN caching. A 24-hour TTL for product images means those images remain valid in every edge server without revalidation. A 5-minute TTL for pricing data means prices refresh frequently enough to feel current while still reducing origin requests by orders of magnitude. A 0-second TTL (no-cache directive) means the edge must revalidate with the origin before serving, turning the CDN into a transparent proxy for that request.
Cache keys determine whether two requests hit the same cached object. By default, the URL is the cache key—/images/product-123.jpg is one cached object, and product-124.jpg is another. But CDNs support more sophisticated keying: including query parameters (so ?size=large and ?size=small are different cache entries), cookies (critical for personalized content), and headers (like Accept-Encoding for compression variants). If you don’t configure the cache key carefully, you might cache the wrong variant.
The Vary header enables content negotiation in caches. When your origin returns Vary: Accept-Encoding, you’re telling edge caches to maintain separate cached versions for gzip and brotli encodings. When you return Vary: Accept-Language, you create separate cache entries for English, French, and German versions of the same URL. This is powerful but demands careful configuration—an accidental Vary on a low-cardinality header can fragment your cache unnecessarily.
Cache tiers in modern CDNs create hierarchies to reduce origin load. L1 edge caches closest to users serve frequently requested content. L2 regional shield caches sit between edges and the origin, absorbing requests from multiple edge servers. When an L1 miss occurs, it pulls from L2; when L2 misses, it queries the origin. This reduces origin traffic exponentially for popular content while maintaining reasonable latency for less popular requests.
Advanced directives like stale-while-revalidate and stale-if-error add resilience and performance. The header Cache-Control: max-age=3600, stale-while-revalidate=86400 tells edges to serve the cached response for 3,600 seconds, but if you need it after that, keep serving the stale copy in the background while revalidating with the origin. If the origin is down, stale-if-error=86400 permits serving stale content for 24 hours instead of returning an error.
Caching Content in the Real World: The Newspaper Analogy
Imagine managing a national newspaper distribution network. The morning edition prints once at 6 AM, and every newsstand receives copies that remain on shelves all day—high cache TTL. Breaking news at 2 PM requires printing a special edition and rushing it to select newsstand regions—short TTL and targeted invalidation. Live sports scores update every few minutes, requiring frequent refreshes or no caching at all.
A modern e-commerce CDN follows the same pattern. Product images from your catalog almost never change, so they receive 30-day TTLs—essentially “set it and forget it.” Inventory counts change throughout the day, so they get 60-second TTLs. The shopping cart is personalized per user and must never be cached—it carries a no-cache directive. This mixed approach maximizes cache efficiency while guaranteeing correctness for sensitive data.
HTTP Headers and Cache Directives: The Technical Reality
The Cache-Control header is your primary tool. Here’s its anatomy:
Cache-Control: public, max-age=3600, stale-while-revalidate=86400
public: This content can be cached by any cache (edges, browsers, proxies).private: Only browser caches can store this; CDN edges must not cache it.max-age=3600: Cache this for 3,600 seconds (1 hour) before revalidation.stale-while-revalidate=86400: After expiry, keep serving stale content for 24 hours while revalidating in the background.must-revalidate: After expiry, you must revalidate—never serve stale content.
ETag and Last-Modified headers enable conditional requests and efficient revalidation. When an edge’s cached response expires, it sends the ETag back to the origin: “I have version xyz—is it still current?” The origin responds with 304 Not Modified (if unchanged) or new content (if changed). This saves bandwidth compared to transferring the entire body.
Surrogate-Control is a CDN-specific variant of Cache-Control that applies only to CDN caches, not browser caches. You might set Cache-Control: max-age=60 for browsers (tight freshness) and Surrogate-Control: max-age=3600 for edges (looser freshness):
Surrogate-Control: max-age=3600, stale-while-revalidate=86400
Cache-Control: max-age=60, public
Purge vs. Invalidate vs. Soft Purge describe different cache invalidation techniques:
| Technique | Behavior | Use Case |
|---|---|---|
| Hard Purge | Immediately remove from all edge caches. Subsequent requests hit origin. | Critical data changes; security issues. |
| Soft Purge | Mark as stale but keep in cache. Next request revalidates with origin. | Non-critical updates; reduces origin spike. |
| Invalidate | Remove based on patterns (URLs, tags). | Bulk updates after deploy. |
Surrogate-Key (or Cache-Tag) invalidation lets you group cached objects and purge them together:
Surrogate-Key: product-123, inventory, category-electronics
When inventory updates, you purge all objects tagged inventory, refreshing product pages and inventory widgets simultaneously without affecting unrelated content.
Origin shielding reduces origin load by inserting a shield cache between edges and origin. All edge requests for the same object route through the shield, turning 1,000 edge requests into 1 shield request. For frequently accessed content at scale, shields reduce origin traffic by 90%+ and are nearly mandatory.
Negative caching caches error responses (404, 403, 500) for short periods. If a user requests a non-existent product page, caching that 404 for 60 seconds prevents the origin from being hammered by repeated requests for the same missing page. Configure this carefully—caching 500 errors can mask genuine outages.
Here’s a decision flowchart for cache configuration:
graph TD
A["Receive Request"] --> B{"Content Changes\nFrequently?"}
B -->|Yes, Daily+| C["Short TTL\n5-60 minutes"]
B -->|No, Weekly+| D["Medium TTL\n1-7 days"]
B -->|Never| E["Long TTL\n30+ days"]
C --> F{"Personalized\nPer User?"}
D --> F
E --> F
F -->|Yes| G["Use Cache-Tag\nInvalidation"]
F -->|No| H["Simple TTL\nBased Cache"]
G --> I["Add Surrogate-Key\nHeaders"]
H --> J["Configure\nETag/Last-Modified"]
Configuring Your E-Commerce Cache Strategy
Let’s walk through a realistic scenario: building a cache strategy for an online retailer.
Product images almost never change. A photo of a blue shirt from last year is still valid today. Configure with:
Cache-Control: public, max-age=2592000, immutable
(2,592,000 seconds = 30 days). The immutable directive tells browsers and edges never to revalidate—you’ve promised this URL’s content never changes.
Product pricing changes throughout the day during sales and inventory adjustments. Use:
Cache-Control: public, max-age=300, stale-while-revalidate=3600
(5 minutes of fresh content, then serve stale for an hour while revalidating). During a flash sale, you might purge the pricing cache immediately to reflect new prices within seconds.
Shopping cart data is personalized and sensitive. Use:
Cache-Control: private, max-age=0, must-revalidate
(or simply no-cache). Browsers cache it, CDNs never do, and it’s always revalidated with the server before serving.
Product catalog pages contain images, text, and links—mostly static but occasionally updated descriptions. Use:
Surrogate-Key: product-123, category-electronics
Cache-Control: public, max-age=1800
When you update a product description, purge via the product-123 tag, refreshing the page within seconds across all edges.
Homepage content changes weekly with seasonal promotions. Use:
Cache-Control: public, max-age=600, stale-while-revalidate=86400
(10 minutes fresh, serve stale for a day if the origin is slow). The homepage receives heavy traffic; revalidation is cheap compared to cache misses.
When deploying new code that changes CSS, JavaScript, or templates, you have two options: cache-busting via URLs or purge-based invalidation. Cache-busting appends a version hash (e.g., bundle-abc123.js), ensuring new requests always hit fresh content without purging. Purge-based invalidation immediately removes old content, forcing all subsequent requests to the origin temporarily (potential origin spike).
Pro tip: Use both. Hash your static assets for cache-busting (browsers and edges automatically fetch new URLs) and tag-based purging for HTML and dynamic content (controlled refresh without URL changes).
Freshness vs. Performance: The Eternal Trade-off
Longer TTLs improve performance and reduce origin load, but stale content risks serving outdated information. Shorter TTLs guarantee freshness but generate more origin requests. The key is matching TTL to content volatility: stock prices need 5-second TTLs, while product descriptions can use 24-hour TTLs.
Purge latency creates another tension. Hard purging immediately removes content from all edges, but coordinating across thousands of edge servers takes seconds to minutes. Soft purging is faster (marking as stale), but users might briefly see outdated content before revalidation. For critical security updates, accept the latency cost; for minor tweaks, soft purging is preferable.
Over-caching leads to serving stale data—a product still marked in-stock after selling out. Under-caching creates origin storms when traffic spikes beyond cache hit ratios. Monitor cache hit rates and adjust TTLs based on user traffic patterns. A 90%+ hit rate for images is typical; a 50%+ hit rate for dynamic pages is healthy.
Personalized content complicates caching. If you cache a user’s profile page with their name and preferences, the cache key must include their user ID, fragmenting the cache. Alternatively, serve static HTML and inject personalization via JavaScript, keeping the cached response generic. This is an active area of innovation; modern CDNs support edge-side includes and worker scripts to render personalized content in the CDN itself.
Key Takeaways
- Cache-Control headers are the primary mechanism for instructing CDNs how to cache content—master
max-age,stale-while-revalidate, andstale-if-errordirectives. - TTL strategy depends on content volatility: static assets get long TTLs (days/months), dynamic content gets short TTLs (minutes/seconds), and sensitive data gets no caching.
- Cache keys (URL, query params, headers, cookies) determine whether requests hit the same cached object—configure them intentionally to avoid fragmenting your cache.
- Surrogate-Key (Cache-Tag) invalidation enables bulk purging without waiting for TTL expiration, critical for rapid content updates.
- Cache tiers and origin shielding reduce origin load by orders of magnitude—multi-tier caches are standard in modern CDNs.
- Stale-while-revalidate and stale-if-error add resilience by serving outdated content rather than errors, improving user experience during origin latency or outages.
Practice Scenarios
Scenario 1: Flash Sale Pricing Your e-commerce site runs a flash sale every Friday at 2 PM. Product prices need to reflect the sale within 5 seconds of the sale start. Current cache TTL for pricing pages is 30 minutes. Design a cache invalidation strategy that updates prices quickly without spiking origin load.
Scenario 2: Multi-Region Personalization Your SaaS platform serves user dashboards from a global CDN. Each user sees their own data, budget, and activity. Naive caching (including user ID in the cache key) fragments the cache across millions of users. Propose an alternative caching approach using edge-side rendering or JavaScript injection.
Scenario 3: Resilient Degradation
Your origin database goes offline for 30 minutes during maintenance. Users attempting to view product pages receive 500 errors, and the CDN propagates these errors immediately (no negative caching configured). How would negative caching combined with stale-if-error have mitigated this?
Connection to Dynamic Content Acceleration
CDN caching strategies work best for static and semi-static content. But what about truly dynamic content—real-time data, personalized recommendations, live user-generated content? In the next chapter, we’ll explore Dynamic Content Acceleration, techniques that use edge computing, request coalescing, and origin optimization to minimize latency for content that cannot be cached. You’ll learn how modern CDNs blur the line between cached and dynamic content, improving performance even for responses that change on every request.