A user in Tokyo requesting a file served from a single origin in Virginia pays for every millisecond of that round trip. A CDN caches copies of your content at edge locations close to users worldwide — so most requests never reach your origin at all. Knowing exactly what gets cached, and how to invalidate it, is the difference between a CDN that helps and one that silently serves stale data.
4 min read
A content delivery network is a globally distributed set of servers (edge locations or points of presence) that sit between users and your origin server. The first request for a resource from a given edge location is a cache miss — the edge fetches it from your origin, serves it, and stores a copy. Every subsequent request for that same resource from nearby users is a cache hit — served directly from the edge, without touching your origin at all.
The win is twofold: lower latency (physically closer server) and lower origin load (most requests never reach it).
Not everything is safe to cache. Static assets — JS bundles, CSS, images, fonts — are the obvious case: they're identical for every user and change only on deploy. API responses are trickier: a GET /products/123 response might be safe to cache for a minute if it's the same for everyone, but a GET /users/me response is per-user and must never be cached and served to a different user.
Whether something gets cached, and for how long, is controlled by the Cache-Control HTTP header from your origin:
Cache-Control: public, max-age=31536000, immutable # static asset with a hashed filename — cache forever
Cache-Control: public, max-age=60 # API response, safe to serve stale for up to 60s
Cache-Control: private, no-store # per-user data — never cache at a shared edge
public means shared caches (CDNs) may store it; private means only the end user's own browser may. max-age is the TTL in seconds. Getting this header wrong in either direction is costly: too permissive and you leak one user's data to another; too conservative and you lose the entire benefit of the CDN.
A CDN decides whether two requests are for the "same" resource using a cache key, typically built from the URL plus a configurable set of headers or query strings. By default, /products?id=123 and /products?id=456 are different cache keys — correct. But if your API returns different content based on an Authorization header or Accept-Language header and that header isn't part of the cache key, the CDN will happily serve one user's response to another. This is one of the most common real-world CDN bugs: forgetting to vary the cache key on something that actually changes the response (Vary: Accept-Language, Vary: Authorization).
"There are only two hard things in computer science: cache invalidation and naming things" is a cliché because it's true. Once content is cached at dozens of edge locations worldwide, getting a stale copy out of all of them is genuinely hard. Two practical strategies:
app.a1b2c3.js), set an effectively infinite max-age, and change the filename on every deploy. Old cached copies simply become unreferenced — no invalidation needed, because nothing ever points to the stale URL again.og-image.png referenced by a fixed URL, an API response), you actively tell the CDN "this path is now stale" (e.g., a CloudFront invalidation request). This is slower (can take seconds to minutes to propagate globally) and, on some CDNs, costs money per invalidation — so it should be the exception, not the default deploy step.Time-to-first-byte from a nearby edge is often 10–20x faster than a cross-continent round trip to origin. For a page with dozens of assets, that compounds — every cached asset is one less round trip contending for the user's connection. A CDN misconfigured to bypass cache on static assets (or one that never gets invalidated on dynamic content) throws away most of that benefit in either direction.
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. What does the Cache-Control header 'private, no-store' communicate to a CDN?
2. An API's response varies based on the Accept-Language header, but the CDN's cache key doesn't include it. What happens?
3. Why does the versioned-URL (cache-busting) strategy avoid the need for active cache invalidation?
4. Why is explicit CDN purge/invalidation generally treated as the exception rather than the default deploy step?
Cloud Computing & Infrastructure