System Design
Advanced 15 min read System Design

CDN & Edge Computing

A CDN copies static and cacheable content to points of presence (PoPs) around the world so users fetch from a server near them instead of your origin. Cache-Control headers decide what is cacheable and for how long, and edge computing runs small programs at the PoP itself — auth checks, A/B tests, rewrites — before a request ever reaches your origin.

cdnpoint of presenceorigincache-controlpurgeinvalidationedge computingTTLanycastworkers
Introduction

What is this?

A CDN (content delivery network) is a network of edge servers at points of presence (PoPs) worldwide that cache copies of your content and serve it to users from the nearest PoP. DNS/anycast routes each user to a nearby PoP, and only cache misses travel to your origin. Cache-Control headers define what is cacheable and for how long; purging or versioned URLs handle invalidation. Edge computing pushes small logic — routing, auth, A/B tests — onto the PoPs themselves, removing the round trip to origin for that work.

Motivation

Why do you need it?

  • Serving from a nearby PoP cuts round-trip time from hundreds of milliseconds to tens, transforming first-load performance.
  • PoPs absorb the vast majority of static traffic, so your origin serves a tiny fraction of the requests it would otherwise.
  • The CDN's global edge provides built-in DDoS absorption and TLS termination near the user.
  • Cacheable API responses can be served from the edge, scaling read-heavy endpoints without touching your servers.
  • Edge computing runs latency-critical logic geographically next to users, where every millisecond counts.
Think about it

Mental model

Imagine

One downtown library and readers across the city

Think of

Small neighborhood kiosks plus one central archive

Readers grab popular books from their local kiosk (PoP) without traveling downtown; only rare requests reach the archive (origin). If a book is recalled, the kiosk's copy is pulled (purged) and the next reader fetches a fresh one from the archive — one expensive trip instead of thousands.

Mechanics

How it works

  • DNS or anycast resolves the client to the nearest PoP, minimizing network distance before the first byte.
  • The PoP looks up the request in its edge cache keyed by URL (plus any Vary-relevant headers).
  • On a hit, the PoP returns the cached object immediately without contacting the origin.
  • On a miss, the PoP fetches from origin, honors Cache-Control to decide what to store and for how long, and caches it.
  • Invalidation happens by purging the URL or by releasing new versions under new URLs (immutable hashed assets).
  • Edge workers intercept requests at the PoP to run small programs before or after the cache.

Anycast routes the user to the nearest PoP; cache misses pull from origin once and are then served locally.

User request
Anycast / DNS
Edge cache lookup
Cache hit?
Origin fetch
Cache + respond
Reference

Key commands

curl -sI https://cdn.example.com/assets/app.v1.js

Inspect the response headers a CDN will honor.

HTTP/2 200\ncache-control: public, max-age=31536000, immutable\nx-cache: HIT
curl -sI https://cdn.example.com/assets/app.v1.js | grep -i cache-control

Quickly view just the caching policy.

npx wrangler deploy

Deploy a Cloudflare Worker (edge function) to every PoP.

Successfully deployed your Worker to ...
dig +short example.com

Resolve the domain and see which PoP IPs are returned by anycast.

104.18.24.25\n104.18.25.25
curl -X POST 'https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache' -H 'Authorization: Bearer TOKEN' -H 'Content-Type: application/json' --data '{"purge_everything":true}'

Purge the entire edge cache for a zone (use carefully).

curl -sI 'https://example.com/account/me' -H 'Cache-Control: no-cache'

Test a cache-bypass request to compare edge vs origin behavior.

Hands-on

Examples

Cache-Control policy on an origin (nginx)

Cache-Control policy on an origin (nginx)
# origin nginx.conf - declare what the CDN may cache
server {
listen 80;
root /srv/www;
# Versioned static assets: safe to cache for a year
location /assets/ {
add_header Cache-Control "public, max-age=31536000, immutable";
try_files $uri =404;
}
# Dynamic API: never cached at shared layers
location /api/ {
add_header Cache-Control "no-store";
proxy_pass http://127.0.0.1:8000;
}
# HTML: cache briefly at the CDN, never in the browser
location / {
add_header Cache-Control "public, s-maxage=60, max-age=0";
}
}

The asset path serves files whose names include a content hash, so 'immutable, max-age=31536000' lets browsers and CDNs cache for a year with no revalidation. The API path uses 'no-store' so private data never lands in a shared cache. The HTML root uses s-maxage=60, which tells the CDN (shared cache) to hold the page for 60 seconds while the browser caches nothing — the standard recipe for serving dynamic-but-briefly-cacheable pages from the edge.

Real world

In production

  • Static assets, images and video are served from PoPs with immutable hashed URLs, so the origin rarely sees static traffic.
  • Global product APIs cache GET responses at the edge with short s-maxage TTLs, cutting origin load for read-heavy public endpoints.
  • Edge workers run geo-aware redirects, device-based content selection and A/B test assignment before origin round trips.
  • Origin shielding and tiered caching keep the origin's connection count low even when millions of users cold-cache the same object.
Guidelines

Best practices

  • Set an explicit Cache-Control on every response — public/private/no-store — so no cache guesses wrong with heuristics.
  • Version asset URLs with content hashes and mark them immutable; purge by version instead of clearing the cache on every deploy.
  • Use s-maxage for shared/edge caches and a separate max-age for the browser so the two layers can differ.
  • Cache only cache-key-stable data: strip cookies and random query parameters from cache keys, and set Vary where truly needed.
  • Configure origin shield so thousands of PoP misses collapse into a single origin connection, not a thundering herd.
Watch out

Common mistakes

  • Shipping no Cache-Control headers and letting caches apply default heuristics that cache private HTML.
  • Caching personalized or authenticated content in a shared cache, leaking one user's page to another.
  • Forgetting Vary for language or device, so the first visitor's language is served to everyone.
  • Bumping URLs by git commit but never purging old keys, leaving the cache to fill with orphaned objects.
Root cause analysis

Common issues

Error
Users still see yesterday's assets after a deploy
Root cause

Assets were marked immutable with a year-long max-age and the URLs were not versioned.

Fix

Bump the URL (app.v1.5.js) or purge the old path; versioned URLs make deploys instant without purging.

Error
Cache miss on every request for the same URL
Root cause

The cache key changes per request because cookies or a random query parameter are part of it.

Fix

Normalize the cache key (ignore cookies and tracking parameters) and only include Vary-relevant headers.

Error
One user sees another user's account page
Root cause

Authenticated or personalized responses were cached in a shared layer.

Fix

Send Cache-Control: private or no-store on authenticated responses, and never store Set-Cookie responses at the edge.

When things break

Debugging tips

  • Read the cache status header (CF-Cache-Status, X-Cache, Age) to see whether a response was HIT, MISS or EXPIRED.
  • Compare the same URL from two regions (VPN or curl with different egress) to confirm PoP behavior is consistent.
  • Bypass the cache with a unique query parameter or Cache-Control: no-cache to see the true origin response.
  • Inspect CDN analytics for per-URL hit ratio and eviction to find content that misses constantly.
Interviews

Interview checkpoint

Practice

Hands-on lab

Simulate a CDN Edge with NGINX Caching
40 min · advanced
In progress
Objectives
  • Run a simple origin server with cacheable and non-cacheable routes
  • Configure an NGINX edge with proxy_cache in front of it
  • Prove MISS -> HIT behavior on repeat requests
  • Understand how TTL headers and purging control staleness

Simulate a CDN Edge with NGINX Caching

40 min · advanced

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which Cache-Control header makes a versioned static asset cacheable for a year without revalidation?

2

A CDN cache miss is always slower than fetching directly from the origin.

3

A personalized dashboard leaks other users' data when served through the CDN. What is the root cause and fix?

Quick reference

Cheat sheet

Cache-Control matrix
public, max-age=31536000, immutableVersioned static assets
public, s-maxage=60, max-age=0HTML: edge caches 60s, browser caches nothing
private, max-age=300Per-user, browser-only cache
no-storeNever cache anywhere
Vary: Accept-LanguageSeparate cache entries per header
Diagnostics
CF-Cache-Status / X-CacheHIT, MISS or EXPIRED
Age headerSeconds the object has been in the cache
curl -sI URLInspect the full policy
?cache-bust=1Force a miss for testing
Purge APIInvalidate by URL or tag
Go deeper

Official documentation