How does a CDN's architecture actually work — origin, edge PoPs, cache hierarchy, and invalidation?
A CDN is a globally distributed caching layer that intercepts requests before your origin ever sees them — its tiers explain both its speed and its invalidation headaches.
LEARN BY DOINGPut your intuition to work3 steps
How does a CDN's architecture actually work — origin, edge PoPs, cache hierarchy, and invalidation?
Use the lesson’s examples and explanation to check your idea.
Personal reflection. Nothing is sent to an AI service.#What problem a CDN actually solves
Every byte a user downloads has to travel the physical distance between where it's stored and where they are, and that distance is latency you can't optimize away with faster code — only with less distance. A CDN (content delivery network) solves this by keeping copies of responses at servers scattered around the world, close to users, so a request from Tokyo doesn't need to round-trip to an origin in Virginia every single time. The same layer also happens to shield the origin from traffic entirely: a well-cached site might serve 95%+ of requests without the origin ever seeing them, which is as much a capacity and resilience story as a latency one.
#Anatomy: origin, edge PoPs, and a mid-tier shield
The origin is the actual source of truth — your application servers or object storage, the only place that can produce a response the CDN has never seen before. Edge servers, deployed at PoPs (points of presence) — hundreds of small facilities distributed globally — are the layer closest to users; a client's TLS connection terminates there, and if the requested object is cached at that PoP, the response never leaves it.
Between hundreds of small edge PoPs and a single origin sits an optional but important mid-tier (sometimes called a "shield" or "regional" cache): a much smaller number of larger regional caches. Without this tier, every one of the hundreds of edge PoPs would independently query the origin on its own first cache miss for a given object — hundreds of simultaneous origin requests for the same content. With a shield tier, edge PoPs miss to the regional cache first; only the regional cache (one per region, not one per PoP) ever talks to origin, collapsing hundreds of potential origin hits into a handful.
Routing a client to a nearby, healthy PoP is usually done via anycast IP addressing (the same IP announced from many locations, with network routing sending the client to the topologically closest one) or geo-aware DNS.
#The request path, including a cache miss
Every miss that reaches origin populates the caches on the way back down, so the next request — from any user near that same PoP — becomes a hit. This is why cache hit ratio climbs quickly after a deploy or a cold start: the first request per object per region pays the full round trip, every subsequent one doesn't.
#Cache keys and freshness signals
What actually gets cached under what key matters as much as whether caching happens at all. The default cache key is the request method plus the normalized URL, but real systems often need to vary the cached response by specific headers or query parameters (a Vary: Accept-Encoding header, for instance, means gzip and non-gzip responses are cached separately). Over-including things in the cache key — varying on a header that's nearly always the same, or on a session cookie that's different for every user — fragments the cache into effectively one entry per request, destroying the hit ratio.
Freshness is controlled by response headers from origin: Cache-Control: max-age=300 tells any cache the response is fresh for 300 seconds; s-maxage overrides that specifically for shared caches like a CDN, letting you keep something fresh longer at the edge than in an end user's browser; public/private controls whether shared caches may store it at all; and no-store opts a response out of caching entirely. ETag plus If-None-Match support cheap revalidation — the cache can ask origin "has this changed since this version?" and get a 304 Not Modified instead of re-downloading the whole body when it hasn't.
#Invalidation: the hard part
Setting a TTL is invalidation by default — content simply expires after N seconds. It's simple and requires no coordination, but it means every cached object goes stale for up to the TTL duration on every update, an acceptable trade for most content but not for something that must be correct within seconds (like a price change).
Active invalidation flips that: a purge API call tells the CDN "this URL is no longer valid," which then has to propagate that instruction out to every PoP that might be holding a copy — genuinely expensive at global scale, since it's effectively a broadcast to hundreds of locations, and there's a real propagation delay before it's guaranteed to have taken effect everywhere.
Cache tags (also called surrogate keys) solve a related but different problem: invalidating many URLs that share some property in one call, rather than purging each individually. A product page and its API response and its search-result snippet might all get tagged product:1001; a single purge of that tag invalidates all three without knowing every URL in advance.
The cleanest invalidation strategy is often to avoid needing it at all: fingerprinted, versioned URLs (app.a1b2c3.js instead of app.js) mean a new deploy produces a brand-new URL, so the old cached object never needs to be invalidated — it's just never requested again, and the new URL can be cached as effectively immutable (Cache-Control: public, max-age=31536000, immutable).
#Callouts and edge cases
🧠 Check your understanding
0/3 · 0/3 answered1. What problem does a regional/shield cache tier solve that edge PoPs alone can't?
2. Why can over-including headers or cookies in the cache key destroy hit ratio?
3. What is a cache stampede, and which technique directly addresses it?