Tier 0 · Foundations

CDN & the Edge

Moving bytes closer to users, and the cache key that decides whether it works

⏱ 15 min foundationscachingnetworking

What a CDN actually is

A globally distributed set of reverse-proxy caches — PoPs (points of presence) — that sit between users and your origin. A request goes to the nearest PoP; if it has a fresh copy it answers immediately, otherwise it fetches from origin and keeps a copy.

Two mechanisms do the work:

Anycast routing. The same IP address is advertised from every PoP, and internet routing delivers the packet to the topologically nearest one. No DNS trickery, no client logic, and failover is fast — if a PoP withdraws its route, traffic moves automatically.

Tiered caching / origin shield. PoPs don't each fetch from your origin independently. They fetch from a regional parent cache, which fetches from origin. Without this, a popular uncached object triggers a simultaneous fetch from every PoP — a thundering herd proportional to the CDN's size. The shield collapses that into one request.

The cache key is the whole game

A CDN caches a response against a key. By default the key is the URL, but everything that gets added to it multiplies your object count and divides your hit rate.

Things that commonly and accidentally wreck the key:

The corresponding discipline: serve static assets from a path or host with no cookies at all, normalise query strings, and be deliberate about Vary.

Cache-Control, precisely

These directives get misused constantly:

Directive Meaning
max-age=N Fresh for N seconds, for any cache
s-maxage=N Same, but for shared caches only — overrides max-age at the CDN
public Cacheable by shared caches even if normally it wouldn't be
private Browser may cache; CDN must not
no-cache May store, but must revalidate before use — not "don't cache"
no-store Must not store at all. This is the one people mean when they write no-cache
immutable Never revalidate within the freshness window
stale-while-revalidate=N Serve stale for up to N seconds while refreshing in background
stale-if-error=N Serve stale for up to N seconds if the origin is failing

The pairing that solves most problems: s-maxage long at the CDN, max-age short in the browser. You can purge the CDN; you cannot purge a browser. Keep the copy you control long-lived and the copy you don't short-lived.

stale-if-error deserves special mention: it turns an origin outage into stale-but-working content instead of an error page. It is close to free resilience and routinely unused.

Invalidation

Versioned URLs (fingerprinting)app.a4f9c2.js. The content hash is in the filename, so a change produces a new URL that was never cached. Combine with max-age=31536000, immutable. This is the correct approach for build assets, and it needs no purge at all.

Purge / invalidate — tell the CDN to drop an object. Necessary for content at stable URLs (an article, a product page). Purges take seconds to propagate globally and are typically rate-limited, so don't design a system that purges thousands of objects per minute.

Surrogate keys / cache tags — tag responses (product-1234, category-shoes) and purge by tag. One product update invalidates every page that displays it. This is the feature that makes CDN-caching dynamic HTML genuinely practical, and it's the thing to reach for when an interviewer asks how you'd cache a content site.

Caching dynamic content

Static assets are the easy half. The gains are larger on dynamic content, and so is the risk.

When not to use one

What to take away

Check yourself

  1. Your CDN hit rate is 4%. What is the most likely cause?

  2. What does Cache-Control: no-cache actually instruct a cache to do?

  3. Why does a CDN use tiered caching or an origin shield?

  4. You need build assets to update instantly on deploy without ever issuing a purge. What is the standard approach?