CDN and edge caching
Cache keys, TTLs, purging, stale-while-revalidate, edge compute, and origin shielding.
The best cache is the one that never hits your origin. A CDN turns "my origin is overloaded" into "my origin is bored" — if you use it right.
Read this if your last attempt…
- You mentioned "we'll put a CDN in front" without details
- You can't explain push vs pull
- You don't have a cache-key design
- You haven't thought about purge
The concept
A CDN (Content Delivery Network) is a distributed cache of your origin's responses, located near users. Done right, it absorbs 80–99% of your traffic at the edge, leaving the origin to handle misses and writes.
Push vs pull:
- Pull CDN (default) — origin serves; edge caches on first miss; subsequent requests hit the cache until TTL expires. Zero upfront work; cold-start misses cost origin. Cloudfront, Cloudflare, Fastly default.
- Push CDN — you pre-upload assets (or pre-warm on deploy) to the edge. No cold-start cost. Right for predictable large assets (JS bundles, video).
Cold request → origin miss → populate. Warm requests → edge hit. Purge or TTL expiry → re-populate on next miss.
Content types — caching strategy.
| Content type | TTL | Cache key trick |
|---|---|---|
| Static assets with content hash (app.a1b2c3.js) | 1 year (immutable) | Hash in filename — new version = new URL |
| HTML shell | 60 s or stale-while-revalidate 300s | Vary on language, not user |
| Public API GET | 5–60 s | Strip user tokens if response is public |
| Personalised API | No edge cache; origin cache only | Vary on user id would explode cardinality |
| Large media (video, images) | Very long; purge rarely | URL-based; origin immutable |
How interviewers grade this
- You name the cache key design (URL + which headers/params vary).
- You state the TTL per content class (static assets: 1y + hash; HTML: 60s; API responses: 5s or no-cache).
- You have a purge story for emergencies.
- You distinguish cacheable (GET, idempotent, shared) from non-cacheable (POST, user-specific).
- You size the expected hit rate and its effect on origin load.
Variants
Pull CDN (default)
Cache on miss; serve from edge on hit.
The zero-setup option. Works for most web traffic. Cold cache after a deploy is a measurable spike on origin; mitigate with staggered purges or pre-warming the top N URLs.
Pros
- +No upload step
- +Handles unpredictable URL space
- +Works with dynamic content
Cons
- −Cold-start miss tax
- −TTL tuning is an art
- −Stale content between change and TTL expiry
Choose this variant when
- Most web apps
- Unpredictable URL space
Push CDN for large static
Upload assets on deploy; edge has them before the first request.
Right for video, large JS bundles, software downloads — anywhere cold-start is expensive or predictable. Often combined with pull for the long tail.
Pros
- +No cold-start miss
- +Predictable origin load
- +Great for large files
Cons
- −Upload step in CI/CD
- −Only useful for known-in-advance assets
Choose this variant when
- Video / software / images
- Large known asset sets
Stale-while-revalidate
Serve stale cached response; refresh in background.
Users never see the cache-miss latency; staleness window is bounded by SWR duration (usually seconds). Perfect for near-real-time dashboards, listings, most HTML.
Pros
- +Always-fast reads
- +Background refresh hides origin hiccups
- +Simple header contract (Cache-Control: max-age=60, stale-while-revalidate=300)
Cons
- −Serves slightly stale content by design
- −Requires CDN support (most modern CDNs have it)
Choose this variant when
- Near-real-time freshness acceptable
- Lists, HTML shells, semi-public API responses
Worked example
Design: CDN for a news site.
- index.html: TTL 60 s, stale-while-revalidate 300 s. Vary on Accept-Language. Purge on publish of a homepage-featured article.
- Article pages (/a/:slug): TTL 10 min, SWR 1 h. Purge on article edit.
- Static assets (bundles, images): 1 year TTL + content hash in filename. Never purged — new version = new filename.
- Images with URL-based resize (/img/:id?w=300): TTL 1 day; Origin rewrites w= to a canonical set to avoid cache-key explosion.
- Logged-in user personalisation: NOT cached at CDN. Served by origin behind a Vary: Cookie that disables edge caching when the session cookie is present.
- Comment API (GET): TTL 10 s. No user cookie in the cache key (comments are public).
Expected hit rate: 95%+. Origin load reduction: ~20×. Cold-deploy mitigation: pre-warm top 1000 URLs via a script after deploy.
Good vs bad answer
Interviewer probe
“How do you use a CDN for your site?”
Weak answer
"Put Cloudflare in front. It caches static assets."
Strong answer
"Pull CDN in front of everything. Cache keys: URL + Accept-Language for HTML; URL only for static assets (they have content hashes, so Accept-Encoding is fine). TTLs by content class: 1y immutable for hashed assets, 60s with SWR 300s for HTML shells, 10s for public API GETs. Non-cacheable content (authenticated responses) has Cache-Control: private and is served origin-only. Purge is a last resort — TTLs are tight enough that most content self-refreshes. Expected origin load reduction: 20–50× depending on product."
Why it wins: Cache-key design, per-content TTL ladder, stale-while-revalidate, purge as emergency lever, quantified origin impact.
When it comes up
- Global users and "make it fast worldwide"
- Static assets, images, video, or large downloads
- The interviewer asks how you reduce origin load
- Any read-heavy public surface
Order of reveal
- 11. Pull CDN in front. Default to a pull CDN over everything cacheable, then classify content into static, semi-dynamic, and personalised.
- 22. Design the cache key. Cache key is URL plus the minimum viable Vary. I strip tracking params and never put a session cookie in the key for public content.
- 33. TTL ladder. 1-year immutable for content-hashed assets, 60s + stale-while-revalidate for HTML shells, a few seconds for public API GETs, origin-only for personalised responses.
- 44. Stale-while-revalidate. Serve slightly stale while refreshing in the background so users never eat the cache-miss latency.
- 55. Purge + error policy. Purge is the emergency lever for corrections; and I never let the CDN cache a non-2xx, or it caches my outage.
Signature phrases
- “The best cache is the one that never hits the origin.” — Frames the CDN as the primary traffic absorber, not an afterthought.
- “Cache key is URL plus the minimum viable Vary — strip the tracking params.” — Names the single biggest hit-rate lever.
- “TTL ladder from 1-year immutable assets down to origin-only personalised.” — Shows per-content-class thinking rather than one blanket TTL.
- “Content-hash the filename so a new version is a new URL.” — The clean cache-busting pattern that avoids purges entirely.
Likely follow-ups
?“How do you serve personalised content with a CDN in front?”Reveal
Split the response. Cache the public shell (layout, nav, anonymous content) at the edge with a long TTL, and hydrate the personalised slice with a separate uncached request (or edge-side includes / edge compute that assembles per-user fragments). What you do not do is put the user id in the cache key for the whole page — that drives the hit rate to zero.
?“You ship a deploy at peak and origin falls over. Why, and how do you prevent it?”Reveal
A deploy that changes URLs or triggers a global purge empties the edge, so every request misses and stampedes origin at once. Prevent it by content-hashing asset filenames (old URLs stay cached, new ones warm gradually), pre-warming the top-N URLs after deploy, and staggered/tag-based purges instead of a global flush. Origin should also have request coalescing so concurrent misses for the same key collapse into one fetch.
?“The CDN cached a 500. What now, and how do you stop it recurring?”Reveal
Immediate: purge the affected URLs once origin is healthy. Prevent: origin returns Cache-Control: no-store (or a very short negative TTL like 5s) on error responses, so the edge never holds a long-lived failure. Caching errors turns a 30-second blip into a TTL-long outage — non-2xx should effectively never get a long TTL.
Common mistakes
Every user has a unique session, so every URL becomes uncacheable. Strip the cookie from the cache key, or use Vary: Cookie only when absolutely needed. Personalised content shouldn't edge-cache anyway.
Tracking params (utm_*, fbclid) all different per share → cache key explosion → 0% hit rate. Strip them at the edge before computing the cache key.
"We'll just wait for TTL" is fine for minor changes; unacceptable for publishing errors or security issues. Know how to purge by URL, by tag, or globally, and how long each takes.
Push a deploy at peak → every URL misses → origin load spike → outage. Pre-warm top URLs after deploy, or use staggered purges.
Practice drills
Your CDN hit rate is 40%. You expected 95%. What's likely wrong?Reveal
Cache key is over-varying. Check: (1) tracking query params (utm_*, fbclid) not stripped — every share creates a new key; (2) session cookie in Vary even on public pages; (3) Accept-Encoding or Accept-Language splitting the cache unnecessarily; (4) TTL too short — 5 s means a lot of misses. Canonicalise URLs at the edge, narrow Vary, tune TTL.
You publish a correction to a live article. How fast does every user see it?Reveal
Depends on TTL + purge. If you purge by URL: seconds to minutes for global propagation (varies by CDN). If you wait for TTL: at most the TTL. If stale-while-revalidate: users see stale until their edge node refreshes in the background (next request after TTL). For breaking-news-class changes: purge explicitly. For routine edits: let TTL handle it.
Interviewer: "your CDN caches a 500 error. Now what?"Reveal
You've cached an outage. Users see a 500 until TTL expires or you purge. Fixes: (1) never cache non-2xx responses — Cache-Control: no-store on error responses from origin; (2) purge the affected URLs once origin is healthy; (3) short negative-response TTL (e.g. 5 s) if you must cache errors to protect origin. The CDN should NEVER have a long-TTL cached 500.
Cheat sheet
- •Default: pull CDN. Push for known-large assets.
- •Cache key: URL + minimum viable Vary. Strip tracking params.
- •TTL ladder: 1y immutable hashed assets → 60s HTML with SWR → short API TTLs → origin-only for personalised.
- •Stale-while-revalidate for always-fast reads with bounded staleness.
- •Purge exists; lean on TTLs first.
- •Never put user cookies in the cache key for public content.
Practice this skill
These problems exercise CDN and edge caching. Try one now to apply what you just learned.
Read this if