CDN Caching
CDN caching stores responses at edge nodes geographically close to users, so a request for static (or stale-while-revalidate-able) content is served from the nearest edge instead of the origin. Latency drops from 100+ ms (cross-continent) to 5-30 ms (local edge), origin load collapses to a small fraction of read traffic, and the system becomes resilient to origin failures. The cost is cache coherence: every edge holds its own copy, and invalidation must propagate to hundreds of POPs.
Foundational.
How it works
A CDN (Content Delivery Network) is a globally distributed set of cache servers — called POPs (Points of Presence) or edge nodes — that sit between users and your origin. When a user requests a resource, the DNS resolution routes them to the nearest POP (typically via anycast or EDNS client subnet). The POP serves the request from its cache if it has it; otherwise it fetches from the origin, caches the response, and serves it.
This is fundamentally a cache-aside pattern at the edge: read-through on miss, with TTLs governing freshness. But unlike application-level cache-aside, the CDN cache is geographically distributed — there is no single "cache node," there are hundreds. Each POP maintains its own cache, so the same resource may be cached in 200 different places, with 200 different TTL countdowns, and 200 different invalidation states.
CDN caching is the second layer in the standard cache hierarchy:
client cache → CDN edge → web server cache → app cache → DB cache → DBThe client cache is faster (zero network), but only the CDN can serve a first-visit user from a nearby POP. Client cache is invisible to the operator; the CDN is operator-controlled and observable. They are complementary: client caching handles repeat visits, CDN handles first visits and global latency.
TTLs: max-age vs s-maxage vs stale-while-revalidate.
CDN caching is governed by HTTP cache headers, but with an important nuance: the CDN (a shared proxy cache) has different TTL semantics than a browser (a private cache). The HTTP spec provides separate directives for each.
Cache-Control: max-age=N— applies to all caches (browser AND CDN). The response is fresh for N seconds.Cache-Control: s-maxage=N— applies ONLY to shared caches (CDN, proxy). Overridesmax-agefor the CDN. Use this when you want the CDN to cache for a long time but the browser to revalidate frequently.Cache-Control: stale-while-revalidate=N— the CDN may serve stale content for up to N seconds while it revalidates against the origin in the background. This is refresh-ahead at the CDN layer: hot content never misses.Cache-Control: private— the response is user-specific; CDNs must not cache it (only the user's browser may).Cache-Control: public— explicitly allows shared caches to store the response (needed when basic auth would otherwise make the response uncacheable).
The classic pattern for static assets: Cache-Control: public, max-age=31536000, immutable — cache for a year, no revalidation, no conditional requests. Combined with versioned URLs (content-hashed filenames), this is the gold standard.
For API responses that change occasionally: Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=60 — the browser revalidates every 60s, the CDN caches for 5 minutes, and the CDN may serve stale for an extra 60s while refreshing.
Once a response is cached at hundreds of POPs, updating it requires either (a) waiting for the TTL to expire (minutes to days) or (b) explicitly purging the URL. CDNs offer purge APIs (Cloudflare, CloudFront, Fastly all do), but a global purge takes 10-60 seconds to propagate, and a single purge call does not reach POPs that have evicted the content (no need) or never had it (no need) — that's actually fine. The tricky case is partial purges: purging one URL but not its dependency chain leaves the site in an inconsistent state. The robust pattern is versioned URLs — change the URL when the content changes, and let old URLs age out naturally.
Origin shield — protecting the origin from cache miss storms.
If a piece of content suddenly becomes viral and many POPs miss at the same time, the origin can still see a burst of requests — one from each POP that just missed. For an origin at capacity, this can be enough to take it down. The standard mitigation is an origin shield: a single intermediate cache layer between the POPs and the origin.
POPs (hundreds) → origin shield (1-2 caches) → originWhen POPs miss, they fetch from the shield rather than the origin. The shield collapses concurrent misses: if 100 POPs all request the same URL within 100ms, the shield fetches from the origin once, then serves the result to all 100 POPs. The origin sees one request, not 100. CloudFront calls this a "shield," Fastly calls it an "origin shield," Akamai calls it an "edge origin." The pattern is universal.
Origin shielding also enables more aggressive caching of the cache-miss path: even a no-cache response (must revalidate every time) can be coalesced by the shield so that only one revalidation reaches the origin per interval. This is the same idea as single-flight / request coalescing for cache stampedes, applied at the CDN-to-origin hop.
When to use CDN caching:
- Static assets (JS, CSS, images, fonts, videos). Always.
- Public, slowly-changing data (product catalog, public profiles, landing pages). Short TTL or stale-while-revalidate.
- Global user base. If your users are in one region, an origin cache may be enough; if they are global, a CDN is essential.
- API responses that are public and cacheable (GraphQL persisted queries, public REST endpoints). Use
s-maxageto keep the browser TTL short while the CDN caches longer. - When you need DDoS protection. The CDN absorbs the traffic; the origin sees only misses.
When NOT to use CDN caching:
- User-specific, real-time data (live chat, real-time dashboards).
privateorno-store. - POST/PUT/DELETE responses. CDNs cache GET and HEAD by default; non-idempotent methods are not cached.
- Single-region, low-latency apps where an origin cache would suffice. The CDN adds a hop for first-visit users.
- Highly dynamic content with strict freshness requirements and no
stale-while-revalidatetolerance.
Your API returns a public list of trending products that updates every 5 minutes. You want the CDN to cache aggressively but the browser to revalidate every minute. Which headers do you set?
Pick one answer.
Without an origin shield, a viral URL causes 50 CDN POPs to miss simultaneously and each fetches from the origin. The origin crashes. What would an origin shield have done?
Pick one answer.
You deploy a bug fix to a JS bundle. The bundle is served via CDN at `/app.js` with `Cache-Control: max-age=31536000`. Users report still seeing the bug. Why, and what is the standard fix?
Pick one answer.
Engineering mental model
Mental model. Think of CDN Caching as a deliberate boundary in a system. The boundary exists because something becomes harder to manage when everything is done in one place: latency, scale, failure isolation, consistency, cost, or team ownership. The useful question is not “what does CDN Caching mean?” but “what pressure makes this boundary worth introducing, and what new failure mode does it create?”
Before choosing CDN Caching, name the workload, the critical user path, the dominant bottleneck, the failure you are trying to absorb, and the trade-off you are willing to accept. If you cannot name those five things, the design is probably premature.
// Pseudocode
request = receive()
result = cdn_caching(request)
return result
// Production questions:
// 1. What happens on timeout?
// 2. Can this operation be retried safely?
// 3. What is the bottleneck?Back-of-the-envelope reasoning
Numerical lens: write down traffic, payload size, read/write ratio, peak multiplier and durability target before choosing a component. The numbers should justify the architecture.
Interactive thought experiment: CDN Caching
Change the variables below and predict what breaks first in CDN Caching. The production lab can later reuse these same inputs.
Change one variable at a time. Predict the failure mode first, then move the slider and see whether your mental model matches the simplified system response.
If you are stuck on CDN Caching, start by drawing the request path and marking every network hop, stateful component, queue, cache and failure boundary. Then estimate where the system will saturate.
You increase traffic by 10× in a system using CDN Caching. What should you inspect first?
Pick one answer.
Which statement is the safest engineering habit when using CDN Caching?
Pick one answer.
You have dashboards for traffic, latency, errors and saturation. You can change the architecture, but every change has operational cost.
Production scenario: your system uses CDN Caching, traffic suddenly spikes, and p99 latency doubles. What is your first move?
Interview drill
Answer this without notes: When would you choose CDN Caching, and when would you intentionally avoid it? Mention at least one bottleneck it addresses, one failure mode it introduces, and one alternative. Then quantify the workload you are designing for.
For CDN Caching, reason in this order: what data is hottest, where can it live closer to the caller, what makes it stale, and what happens on a miss or cache failure. A cache is an optimization boundary, not the source of truth.
Numerical sanity check
A useful first-order model is cache_load = request_rate × (1 - hit_rate). If traffic is 20,000 req/s and the hit rate is 90%, roughly 2,000 req/s still reaches the origin before considering misses caused by expiration or eviction.
Do not optimize for a memorized definition. Reason from the workload and failure mode.
You have a read-heavy CDN Caching path. Traffic doubles overnight. What metric would you inspect first, and what would convince you to add another cache layer?
Pick one answer.
What you gain, what you pay
- +Latency drops from 100-220ms (cross-continent) to 4-30ms (local edge).
- +Origin load drops 20-100x — only cache misses reach the origin.
- +DDoS shield — the CDN absorbs traffic; the origin sees only misses.
- +Global horizontal scale — every POP is its own cache, no shared state.
- +Resilient to origin failures — POPs can serve stale content (`stale-if-error`) while the origin recovers.
- −Cache coherence is hard — each POP has its own cache; invalidation must fan out.
- −Cost — CDNs charge per GB transferred ($0.01-0.10/GB), can become expensive at video scale.
- −First-visit miss — every URL must be fetched from the origin once per POP.
- −Non-cacheable content (POST, user-specific) bypasses the CDN, adding a hop.
- −Vendor lock-in — purge APIs and config differ between Cloudflare/CloudFront/Fastly/Akamai.
How this breaks in production
- Viral URL without origin shield → concurrent misses from many POPs overwhelm the origin.
- Long TTL on non-versioned URL → buggy response cached for months at every POP and browser.
- Purge takes 10-60 seconds to propagate globally → brief window of inconsistency.
- Cache key collisions — including or excluding query params changes the cache key, causing leaks or misses.
- `private` content cached at the CDN due to misconfigured headers → cross-user data leak.
- Stale content served after origin recovers from failure if `stale-if-error` TTL is too long.
Don't fall into these traps
- •Forgetting `s-maxage` — using `max-age` for both browser and CDN when they should differ.
- •Caching user-specific responses without `private` — cross-user data leakage via shared POP caches.
- •Long TTLs on non-versioned URLs — buggy responses cached for the full TTL at every POP and browser.
- •Not enabling origin shield on viral content — origin crashes despite the CDN absorbing 95% of traffic.
- •Treating CDN purge as instant — it is eventual (seconds to minutes); design for the propagation window.
- •Caching POST responses by accident — most CDNs only cache GET/HEAD by default; misconfiguration can cache state-changing requests.
Real systems using this
How real systems implement this
- Netflix Open Connect — Netflix's purpose-built CDN distributes video chunks to ISP-embedded Open Connect Appliances (OCAs) — caching video at the ISP edge so streaming traffic never reaches Netflix's origin. The canonical example of CDN caching for video at planetary scale.
- Cloudflare / CloudFront / Fastly / Akamai — The major commercial CDNs. Cloudflare has 300+ POPs; CloudFront integrates with AWS origin (S3, ALB); Fastly offers instant purges (sub-second); Akamai is the original. All implement `s-maxage`, `stale-while-revalidate`, and origin shielding.
- GitHub raw content and Pages — GitHub serves raw.githubusercontent.com and Pages sites through Fastly, with aggressive caching of static content. Hot JS bundles in popular repos are served from edge POPs globally with sub-30ms latency.
- npm registry / Docker Hub / PyPI — Software package registries use CloudFront/Cloudflare to cache package tarballs at the edge. A globally popular package (e.g., `react`) is served from edge POPs, not from the central registry.
Practice saying it out loud
- Q1Design the caching strategy for a global e-commerce site with static assets, product pages, and per-user cart.
- Q2How would you handle a viral URL on a CDN-backed site to prevent origin overload?
- Q3What is the difference between `max-age`, `s-maxage`, and `stale-while-revalidate`? When would you use each?
- Q4How would you deploy a hotfix to a JS bundle that is CDN-cached with a 1-year TTL?
- Q5When would you NOT use a CDN, even for static content?
Further reading & references
Core explanations are original NO CAP material. External references are provided for deeper study and standards.
What next?
Mark as understood once the mental model clicks.
Next recommended
Web Server Caching