CDN and Static Content
Intuition: a local pickup point instead of a central warehouse
Picture an online store with one giant warehouse outside Chicago. If every order from Seattle shipped from there, a package would take a week and the warehouse would be swamped. So popular products get shipped ahead of time to pickup points near the customers. You grab your package around the corner, and the central warehouse handles the rare orders.
A CDN (Content Delivery Network) works the same way. It's a network of edge servers (edge, PoP) around the world. They hold copies of your files: JS, CSS, images, video. The user gets the file from the nearest node, and your main server (the origin) only responds when the edge doesn't have a copy.
Why static content is served from the edge
Static content is files that are the same for everyone: logo.png, app.js, video thumbnails. It's ideal for caching, and that pays off in three ways:
- Latency. You can't speed up the speed of light. The RTT from Sydney to a server in Virginia is about 200 ms; to a CDN node in Sydney, about 10 ms. TCP + TLS take 2–3 RTTs before the first byte even arrives. So the difference is hundreds of milliseconds on every connection.
- Load on the origin. The edge handles most requests, and only a small share reaches you.
- Bandwidth and resilience. Traffic spikes (a launch, a viral image) and even DDoS attacks land on a huge distributed network instead of your three servers.
Diagram
How the edge cache works
- The user requests
cdn.site.com/app.3f9a2c.js. DNS or anycast routes them to the nearest node. - Cache hit: the file is there and hasn't expired, so the node serves it right away.
- Cache miss: the node goes to the origin (S3, for example), stores a copy, and serves it. The next users in that region get a hit.
How long a copy is kept is decided by the TTL. The origin usually sets it with headers:
HTTP/1.1 200 OK
Content-Type: application/javascript
Cache-Control: public, max-age=31536000, immutable
ETag: "3f9a2c"max-age=31536000 means "keep it for a year," and immutable means "don't even bother revalidating." HTML gets a short TTL or no-cache so users see the new version of a page quickly.
Invalidation: the version in the file name
The big headache with caching is how to update a file that's already spread across a hundred nodes with a one-year TTL. There are two ways:
| Approach | How it works | Downsides |
|---|---|---|
| Purge via the CDN API | "Delete /app.js on every node" |
Slow (seconds to minutes), often paid, and browsers keep their own copy anyway |
| Version in the name | app.3f9a2c.js, where the hash comes from the file contents |
You need a build step that rewrites the links in the HTML |
The second approach is the industry standard. A file with a given hash never changes, so it can be cached forever. A new release produces a new name (app.8b1d07.js), the HTML starts pointing to it, and the old copy simply stops being requested. Nothing needs invalidating: only the HTML needs a short TTL.
Tip: in an interview, put it like this: "We version static files with a hash in the name and cache them as
immutablefor a year, while HTML is served with a short TTL. Purge is for emergencies."
Let's count the savings
Say there are 10 million page views a day with 2 MB of static content each, and a 95% CDN hit rate.
| Quantity | Calculation | Result |
|---|---|---|
| Daily traffic | 10M × 2 MB | 20 TB |
| Average bandwidth | 20 TB / 86,400 s | ≈ 230 MB/s ≈ 1.9 Gbps |
| Peak (×3) | 1.9 × 3 | ≈ 5.6 Gbps |
| To origin (5% miss) | 5.6 × 0.05 | ≈ 0.28 Gbps |
Without a CDN you'd need to push almost 6 Gbps from your own servers. With a CDN, one modest S3 bucket is enough.
CDNs and dynamic content
Even uncacheable requests benefit from a CDN:
- TLS terminates at the edge. The expensive handshake happens with a nearby node, and the CDN already has warm keep-alive connections to the origin over a fast backbone.
- Microcaching. Responses like "top products" or "feed for logged-out users" can be cached for 1–5 seconds. At 10,000 RPS on such an endpoint, only about one request per second per node reaches the origin.
- Keyed caching. Vary by
Accept-Languageor device viaVaryor a custom cache key. - Edge compute (Cloudflare Workers, Lambda@Edge): A/B redirects, JWT checks, geo-blocking right at the edge.
- Protection: WAF, rate limiting, and DDoS absorption before the traffic ever reaches you.
Mark personal data (cart, profile) as Cache-Control: private or no-store so it doesn't end up in a shared cache.
Trade-offs worth naming
- Staleness: until the TTL expires, a user may see an old version. Versioning fixes this.
- Cost: you pay for egress traffic and requests. At large volumes, multi-CDN or your own nodes pay off, like Netflix Open Connect.
- Cold cache: rare files (the long tail) often miss. An origin shield helps: a middle cache layer that collapses misses from different nodes into one request to the origin.
- Harder debugging: "it works for me but not for the user in Tokyo," because you're hitting different nodes.
How it sounds in an interview
"Images and video go into S3 with a CDN in front of it. Static files are versioned with a hash and cached for a year; HTML lives with a one-minute TTL. We expect a 95%+ hit rate, so the origin sees about 5% of the traffic. We use the CDN for the API too: TLS at the edge, microcaching public endpoints for a couple of seconds, and a WAF. Private responses are marked
privateso they don't leak into the shared cache."
Common mistakes
- Updating a file under the same name and hoping purge will save you.
- A long TTL on
index.html: after a release, users are stuck on the old version. - Caching a response with cookies or personal data as
public. - Forgetting the origin shield with a large media catalog: thousands of misses hit the storage directly.
- Saying "a CDN is just for images" and missing the benefits for dynamic content.
If you can draw the diagram above and explain why app.3f9a2c.js can be cached forever, you can handle the CDN topic in an interview with confidence.