Understanding Caching and CDNs — the Layers, the Headers, the Hard Problem

Redaktion ·

Caching is the cheapest performance there is: serving a response that was already computed a second time costs almost nothing. That’s exactly why the web is layered with caches top to bottom — and exactly why wrong caching is one of the most stubborn classes of bug there is. This article explains the layers, the HTTP headers, the role of the CDN, and the one problem that makes it all hard: invalidation.

The cache layers

Between the user and your database sit several stations, each able to cache. From the outside in:

  • Browser cache — the cache right in the user’s browser. Reload a page and it pulls assets from local storage instead of the network. Private, for this one user only.
  • CDN / edge cache — a geographically distributed network of servers (see below). Stores responses close to the user and offloads your origin server.
  • Server / application cache — on your side: rendered pages, computed results, API responses held in RAM or a store like Redis instead of being recomputed on every request.
  • Database cache — the bottom layer: frequent query results the database (or a layer in front of it) keeps ready so not every request hits the disk.

The further out a cache hits, the bigger the saving — a file cached in the browser causes no traffic at all. The further in, the fresher the data, but the more work before delivery.

How HTTP caching headers work

Communication between server and cache runs over HTTP headers. The most important ones:

Cache-Control is the central switch. The key directives:

  • max-age=<seconds> — how long the response counts as “fresh.” Within that time it’s reused without asking back.
  • public / privatepublic may live in shared caches (CDN, proxy), private only in the user’s browser (for personalized content).
  • no-cache — storing allowed, but revalidate with the server before each reuse. Not to be confused with:
  • no-store — don’t store at all. For sensitive data.

ETag and Last-Modified enable revalidation. The server sends an ETag (a hash of the content) or a modification date with the response. Once the cached copy has expired, the client asks back with If-None-Match (or If-Modified-Since): “Do I still have the current version?” If nothing has changed, the server replies with a lean 304 Not Modified — no re-download of the content. ETag is more reliable than Last-Modified and takes precedence during revalidation.

stale-while-revalidate is the elegant compromise: the cache may serve a slightly stale response immediately while fetching a fresh one in the background. The user never waits for the revalidation; next time the response is current. Ideal for content where a few seconds of staleness don’t matter.

What a CDN does

A CDN (Content Delivery Network) is a globally distributed network of edge servers. Instead of every user contacting your single origin server (say, in Frankfurt), the request is routed to the nearest edge node — for a user in Tokyo, to a server in Japan.

Three main jobs:

  1. Static assets closer to the user. Images, CSS, JavaScript, fonts sit cached at the edge. The shorter physical distance noticeably lowers latency and with it TTFB.
  2. Offloading the origin. What the edge serves, your server doesn’t have to. During traffic spikes or viral content, the CDN absorbs the bulk.
  3. Extra duties. Modern CDNs often handle TLS termination, compression (Brotli/Gzip), and partly security filtering (DDoS protection, WAF) — right at the edge, before the request reaches the origin.

Cache invalidation — the hard problem

There’s an old industry joke: the two hardest things in computer science are cache invalidation and naming things. The joke has a true core.

The problem: you want long cache times (for performance), but you also want users to see the current version the moment you change something. These two goals conflict. Set max-age to a year and then change the file, and users with a cached copy see the old one for days.

The clean solution for static assets is cache busting: the filename contains a version hash, like app.v123.css or app.a1b2c3.js. Change the content and the hash changes, and with it the URL — the browser sees a new file and loads it. The old URL stays safely cached for a year because it never shows the same content again.

Practical defaults (per MDN, as of 2026):

  • Versioned static assets (with a hash in the name): Cache-Control: public, max-age=31536000, immutable — one year, never revalidate.
  • HTML documents (fixed URL, no busting possible): Cache-Control: no-cache plus ETag — always revalidate, but just a 304 if unchanged.
  • Personalized / dynamic responses: Cache-Control: no-cache, private.

For CDN caches that can’t be cleared via HTTP headers alone, providers offer an active purge (via API or dashboard) to evict a specific URL from all edge nodes immediately.

The performance and SEO effect

Caching acts directly on the metrics Google measures. A low TTFB — driven largely by CDN and server cache — is the starting gun for all subsequent load phases and feeds into the Core Web Vitals. Consistently fast delivery, even under load, improves the user experience and indirectly the ranking. Caching is therefore not a pure infrastructure topic but an SEO lever.

FAQ

What’s the difference between no-cache and no-store? no-store forbids storing entirely — the response lands in no cache. no-cache allows storing but requires revalidation with the server before each reuse. So no-cache is not “don’t cache” but “cache, but always ask.”

What are ETag and Last-Modified for? Revalidation. Once a cached response has expired, the client asks with the ETag whether it’s still current. If nothing has changed, the server replies with a lean 304 instead of resending the whole content — saving bandwidth and time.

Do I need a CDN if my server is fast? Often yes. Even a fast server sits in one place; users on the other side of the world pay the physical latency. A CDN delivers from the nearest edge node and additionally absorbs load spikes. For a global audience it’s almost always worth it.

How do I update a file cached with max-age of a year? Through cache busting: give the file a new name with a version hash on every change (app.v124.css). The new URL loads fresh, the old one stays harmlessly cached. That’s how you combine long cache times with instant updates.

What does stale-while-revalidate give me? Speed without noticeable staleness. The cache serves a slightly stale response immediately and fetches the fresh one in the background. The user never waits for the update — it’s there on the next visit. Ideal for content where seconds of delay are non-critical.