AnyLearn
All lessons

CDNs Explained

Why your assets should never come from your origin. How a CDN's edge cache, geographic routing, and invalidation actually work, plus the cases where a CDN doesn't help (or quietly hurts).

Updated · AI-authored, review-gated · how lessons are made

Not signed in: your progress and quiz score won't be saved.
Progress1 / 8

What a CDN is

A Content Delivery Network is a fleet of servers ("edges" or "PoPs") distributed worldwide, each holding cached copies of your content. When a user requests a file, the CDN serves it from whichever edge is closest to them — not from your origin in us-east-1.

Three wins:

  1. Speed: a user in Tokyo gets your CSS from a Tokyo PoP in 10ms instead of from Virginia in 200ms.
  2. Origin offload: 95% of asset requests never reach your servers. Your bandwidth bill and capacity needs shrink.
  3. Resilience: a CDN absorbs traffic spikes (and many DDoS attempts) before they hit your origin.

The trade: cached data can be stale, and you have to think about how to invalidate it.

Full lesson text

All 8 steps on one page, for reading, reference, and search.

Show

1. What a CDN is

A Content Delivery Network is a fleet of servers ("edges" or "PoPs") distributed worldwide, each holding cached copies of your content. When a user requests a file, the CDN serves it from whichever edge is closest to them — not from your origin in us-east-1.

Three wins:

  1. Speed: a user in Tokyo gets your CSS from a Tokyo PoP in 10ms instead of from Virginia in 200ms.
  2. Origin offload: 95% of asset requests never reach your servers. Your bandwidth bill and capacity needs shrink.
  3. Resilience: a CDN absorbs traffic spikes (and many DDoS attempts) before they hit your origin.

The trade: cached data can be stale, and you have to think about how to invalidate it.

2. Pull-through vs push CDNs

Two ways content gets to the edge:

  • Pull CDN (the default): edges fetch from your origin on first miss, cache, and serve. You change nothing about how you publish files. Cloudflare, AWS CloudFront, Fastly all default to pull. Use this 95% of the time.
  • Push CDN: you upload assets to the CDN explicitly. The edge serves them; the origin never gets asked. Used for predictable static content, large video libraries, or strict origin-shield requirements.

For most apps, pull is dramatically simpler and works fine. Push starts making sense when origin egress costs matter and you want to control exactly what lives on the edge.

3. Cache hierarchy

A request from your browser passes through several caches in a typical CDN setup:

  1. Browser cache: the user's machine. Fastest; controlled via Cache-Control headers.
  2. Edge PoP: the CDN node serving the user. Most traffic terminates here.
  3. Regional cache / shield: a few large mid-tier caches in front of origin. Coalesces requests from many edges so origin sees one request, not many.
  4. Origin: your servers.

A cache MISS at one layer is a HIT or MISS at the next. Tuning Cache-Control and the CDN's edge TTL controls how long each layer holds onto things. The further down the hierarchy a request reaches, the slower it is.

4. Cache hierarchy in a typical CDN

Each layer absorbs traffic from the next.

flowchart LR
  User["Browser"] --> Edge["Edge PoP"]
  Edge --> Shield["Regional shield"]
  Shield --> Origin["Origin server"]

5. TTLs and Cache-Control

Your origin's Cache-Control header tells everyone downstream how long to cache. Common patterns:

  • Cache-Control: public, max-age=31536000, immutable — assets with content-hashed filenames (app.a8b3.js). Cache forever; new versions get new URLs.
  • Cache-Control: public, max-age=300, s-maxage=3600 — HTML or APIs with mild freshness. Browser caches 5 min; CDN caches 1 hour (s-maxage overrides for shared caches).
  • Cache-Control: private, no-store — user-specific or sensitive responses. Never cached.
  • Cache-Control: public, max-age=0, must-revalidate, stale-while-revalidate=86400 — always check freshness, but tolerate stale during revalidation. The pattern modern frameworks use for most pages.

Get these right and the CDN does the rest. Get them wrong and you ship stale builds for hours.

6. Invalidation: the painful part

Sometimes you need to forcibly clear something from every edge worldwide. Approaches:

  1. Content-hashed URLs: never invalidate at all. New version → new URL (app.a8b3.jsapp.de91.js). The most reliable approach; ideal for build artifacts.
  2. Versioned URLs (?v=42): similar idea; bump the query string to bust caches. Note: some CDNs ignore query strings by default; check.
  3. API-driven purge: most CDNs let you POST a URL to a purge endpoint. Reliable for content you can enumerate (specific pages). Often rate-limited.
  4. Surrogate keys / tags: Fastly and others let you tag cached objects with keys, then purge all objects with a key in a single request. Game-changing for content with cross-cutting dependencies.

Rule of thumb: design URLs so you almost never need to invalidate, then use API purges for the rare case.

7. Edge compute, briefly

Modern CDNs let you run code at the edge — Cloudflare Workers, Fastly Compute, Vercel Edge Functions, AWS Lambda@Edge. The pitch: response generation closer to the user, sub-millisecond cold starts, no origin round-trip.

Good fits:

  • A/B testing routing
  • Auth checks before forwarding to origin
  • Image resizing on the fly
  • Personalisation of cached HTML

Less good fits: anything that needs a database in another region (you've moved the latency, not eliminated it), heavy compute (edge runtimes are constrained), or strong consistency across PoPs (replication latency is real).

Useful, not magic. The shape of the problem still matters.

8. When a CDN doesn't help

CDNs are most powerful for public, cacheable, repeated responses. They help less or not at all for:

  • Per-user dynamic responses: each user gets a different page; nothing cacheable at the edge.
  • Write-heavy APIs: nothing to cache; the CDN is just a passthrough proxy.
  • WebSockets and long-lived connections: CDNs can proxy them but the caching benefit is zero.
  • Geographically uniform audiences: if 99% of your users are in one city, the CDN's geographic spread is wasted (though origin shielding can still help).

In these cases the CDN's value drops to "sane TLS termination + DDoS protection" — still nice, but you wouldn't pay enterprise pricing just for that. Match the tool to the workload.

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. What is the primary purpose of a CDN's regional shield or mid-tier cache?
    • To replace the origin server
    • To coalesce many edge cache-misses into a small number of origin requests
    • To enforce TLS
    • To rewrite URLs
  2. Which approach is the most reliable way to ship a new version of `app.js` without serving stale copies?
    • Lower the CDN's TTL to 1 minute
    • Use content-hashed filenames; old versions stay cached but the new URL is fetched fresh
    • Send a purge request for `app.js` and wait
    • Restart the origin server
  3. When does `Cache-Control: public, max-age=300, s-maxage=3600` apply each value?
    • max-age = browser, s-maxage = CDN/shared caches
    • max-age = origin, s-maxage = browser
    • Both apply to the browser
    • max-age = mobile, s-maxage = desktop
  4. Which workload benefits *least* from a CDN's caching?
    • Public homepage of a marketing site
    • Per-user dashboard rendered server-side from session state
    • Library of static JavaScript bundles
    • Public blog posts
  5. What's a typical reason to use edge functions (Cloudflare Workers, Vercel Edge Functions) instead of pure static caching?
    • Static caches can't handle gzip
    • You need lightweight per-request logic (A/B routing, auth checks, image resizing) close to users without a round-trip to origin
    • Edge functions are always cheaper
    • Static caches don't support HTTPS

Related lessons

Programming
intermediate

Benchmarks That Hold Up, and Knowing When to Stop

A benchmark is an experiment, and most are badly designed enough to produce confident wrong answers. This lesson covers what a measurement must control to mean anything, the ways microbenchmarks lie including code the compiler deletes, how to catch regressions in continuous integration despite noisy machines, and how to recognise the point where optimising stops paying.

7 steps·~11 min
Programming
intermediate

Where Time Actually Goes: The Six Usual Suspects

Slow software is slow for a short list of reasons, and each one has a signature you can recognise before you find the code. This lesson covers the six recurring bottleneck classes, waiting on I/O, chatty queries, allocation pressure, lock contention, memory access patterns and serialisation, with the symptom that identifies each and the fix that actually works.

7 steps·~11 min
Programming
intermediate

How Profilers Work, and How to Read a Flame Graph

A profiler is not a neutral observer: sampling and instrumentation see different things, distort the program in different ways, and answer different questions. This lesson covers how each works, why CPU time and wall-clock time give opposite answers, and how to read a flame graph correctly, including the axis that means nothing and is misread constantly.

7 steps·~11 min
Programming
intermediate

Measure First: The Arithmetic That Decides What to Optimise

Most optimisation effort is spent on code that was never the problem, and the reason is that intuition about where time goes is reliably wrong. This lesson covers why guessing fails, the arithmetic that caps what any optimisation can buy, the difference between latency and throughput, and how to set a target that tells you when to stop.

7 steps·~11 min