Skip to content
fearchitect
Performance Engineering

Caching Strategies

Layer browser, CDN, and app caches to serve responses without re-fetching.

By Abas TurabliReviewed

Summary

HTTP caching, CDN edge caches, and service workers form a layered system. Each layer intercepts requests before they hit the origin. Getting the directives right — especially distinguishing `max-age` from `s-maxage`, or `no-cache` from `no-store` — determines how fresh users' data is and how little your origin pays per request.

Jump to the interview angle

Caching stores a response and reuses it for matching requests. The three main layers are:

  • Browser cache — per-user, governed by HTTP Cache-Control response headers and ETag/Last-Modified validators.
  • CDN / shared cache — sits between origin and many users; respects s-maxage and Surrogate-Control. One cached response serves thousands.
  • App cache (service worker) — JavaScript-controlled, survives offline; you pick the strategy per route.

Cache-Control directives

DirectiveWho it targetsWhat it does
max-age=NBrowserCache for N seconds; no revalidation within TTL
s-maxage=NCDN onlyCDN TTL; overrides max-age for shared caches
immutableBrowserSkip revalidation even on hard refresh
no-cacheBrowser + CDNStore, but revalidate before every use
no-storeBrowser + CDNNever store; use for sensitive data
stale-while-revalidate=NBrowser + CDNServe stale instantly; refresh in background within N seconds

Service-worker stale-while-revalidate

Returns the cached response immediately if present, then refreshes in the background. The next request gets the updated copy.

Service-worker SWR strategyts
// sw.ts — SWR strategy for API routes
self.addEventListener("fetch", (event: FetchEvent) => {
  if (!event.request.url.includes("/api/")) return;

  event.respondWith(
    caches.open("api-v1").then(async (cache) => {
      const cached = await cache.match(event.request);

      // Fetch in background — update cache for next request
      const networkFetch = fetch(event.request).then((res) => {
        if (res.ok) cache.put(event.request, res.clone());
        return res;
      });

      // Serve cached instantly if available; otherwise wait for network
      return cached ?? networkFetch;
    })
  );
});

No framework dependency — works in any service worker. Versioning the cache name (api-v1) lets you invalidate old entries when the SW updates.

Request path through the three cache layers: service worker, CDN, and origin.

The golden rule

Content-hashed static assets (e.g., main.abc123.js) get Cache-Control: public, max-age=31536000, immutable. HTML documents get short TTLs or no-store — they are the entry point, and a stale one breaks everything after a deploy.

Interview angle

Interviewers probe the difference between browser and CDN caches and when to use immutable. Strong answers name the three layers, distinguish max-age from s-maxage, explain that content hashing unlocks forever-caching, and mention stale-while-revalidate as the freshness–speed trade.

Soundbite: "Hash asset filenames, cache forever with immutable; keep HTML TTLs short or use CDN purge on deploy."

Key terms

Cache-Control
HTTP response header carrying cache directives like `max-age`, `s-maxage`, and `no-store`.
ETag
A validator token the server issues; the browser sends it as `If-None-Match` to revalidate without re-downloading the body.
s-maxage
CDN-specific TTL that overrides `max-age` for shared caches; the browser ignores it.
stale-while-revalidate
Directive (and SW strategy) that serves a stale response instantly, then refreshes in the background.
immutable
Tells browsers the resource will never change within `max-age`; suppresses revalidation on hard refresh.

Further reading

Search fearchitect

Jump to a topic, mode, or action.