Module 3 · Lesson 7 of 7
CDNs and browser caches
Caching before the request even reaches you.
So far every cache in this module lives next to your servers. But the fastest request is one that never reaches your servers at all. The band's poster is a 400 KB image that 2 million people will load this week, and a fan in Guwahati is 2,000 km from your data centre in Mumbai. Two more caches can help: one in the fan's own browser, and one in a building down the road from them.
The layers between a fan and your server
A request for the event page's poster can be answered at any of these places, and each one closer to the fan is faster and cheaper for you:
You've already met the right-hand side. This lesson covers the left: the browser cache, which lives on the fan's device, and the CDN (content delivery network), a company running cache servers in hundreds of cities that sit between users and your origin.
The browser cache and Cache-Control
When your server sends a response, it can tell the browser how long it may reuse it. That's what the Cache-Control header is for:
Cache-Control: public, max-age=31536000, immutable
This says "anyone may cache this, it's good for a year, and it will never change". The next time the page needs that file, the browser uses its own copy without sending a request. Zero milliseconds, zero bytes, zero load.
The header's main directives, in plain terms:
max-age=N: reuse this for N seconds without asking.s-maxage=N: the same, but only for shared caches like a CDN. Lets the CDN keep something longer than browsers do.no-cache: you may store it, but check with the server before each reuse. (The name is misleading; it does cache.)no-store: never store it anywhere. For truly private responses.private: only the user's browser may cache it, not a CDN. For pages that differ per user.stale-while-revalidate=N: aftermax-ageruns out, keep serving the old copy for up to N more seconds while fetching a fresh one in the background. This is the early-refresh trick from lesson 3.6, built into HTTP.
Asking "has it changed?" cheaply
When a cached copy runs out, the browser doesn't have to download everything again. If the response carried an ETag (a fingerprint of the content, like "v7-a91f"), the browser can ask:
GET /events/the-band-mumbai/poster.jpg
If-None-Match: "v7-a91f"
If nothing changed, the server answers 304 Not Modified with no body. That still costs a round trip, but not the 400 KB. Last-Modified and If-Modified-Since do the same with timestamps.
Fingerprinted file names: cache forever, change instantly
There's a tension: you want the browser to cache the poster for a year, but when the organiser uploads a new poster you want everyone to see it at once. You can't take back a max-age you've already sent.
The fix is to never change a file at a given URL. Put a hash of the content in the file name: poster.3f9a1c.jpg. The URL is cached for a year with immutable. When the poster changes, the new one is poster.b72e04.jpg, and the event page (cached only briefly) points to the new name. Old copies are never requested again.
Frameworks like Next.js do this automatically for JavaScript and CSS bundles. Do the same for anything users upload.
Cache files forever under names that change when their content changes. Cache the page that points to them only briefly.
What a CDN does for you
A CDN runs cache servers (called edges or points of presence) in many cities. DNS sends each fan to a nearby edge. If that edge has a fresh copy, it answers in about 10 ms. If not, it fetches from your server (the origin), stores the copy, and serves the next thousand fans from there.
For Gatepass, that buys three things:
- Latency. The fan in Guwahati gets the poster in 10 ms instead of 60 ms plus transfer time across the country.
- Origin load. Two million poster loads become a few hundred requests to your servers, one per edge, per expiry.
- Bandwidth cost and spikes. The CDN's network absorbs the announcement surge. Your servers see a gentle trickle.
CDNs are best at static content: images, video, JavaScript, CSS, fonts and ticket PDFs. They can also cache dynamic pages that are the same for everyone, like the public event page, if you give them an s-maxage. Even 5 seconds of edge caching on a page read 20,000 times a second means your origin sees each edge's request once every 5 seconds, not 20,000 times.
Purging and what the CDN can't do
When something cached at the edge must change now, say a cancelled show, most CDNs offer a purge API: tell every edge to drop a URL or a tag. Purges usually take a few seconds to reach every edge worldwide. Treat them like delete-on-write from lesson 3.3: useful, not instant, and backed up by a sensible TTL.
A CDN can't help with anything that must be unique per user and fresh on every request: seat availability during checkout, payment, the booking itself. Those still reach your servers. The goal is that only those reach your servers.
Check yourself
Which Cache-Control header suits the public event page for the band, which changes a few times a day but is read 20,000 times a second?
Your turn
Write the Cache-Control header you'd send for each: the band's poster image, the public event page, a fan's 'My tickets' page, and the JavaScript bundle for the app.
In the URL shortener drill at /drills/url-shortener, think about which responses could carry a cache header. A redirect for a popular link is the same for everyone, which makes it a candidate for edge caching, as long as you're happy to give up exact click counts.
Key takeaways
- The browser and a CDN are caches too, and they sit before your servers. Every request they answer costs you nothing.
Cache-Controlsets the rules:max-agefor browsers,s-maxagefor CDNs,private/no-storefor personal data,stale-while-revalidateto avoid waiting on refreshes.- Fingerprinted file names let you cache static files forever and still change them instantly.
- CDNs cut latency and origin load for static files and for pages that are the same for everyone. Personal pages must never be publicly cached.
Finished reading?
Mark it complete to tick it off in the course.