System-design · Caching Strategies

Caching Strategies Interview Questions
With Answers & Code Examples

6 carefully curated Caching Strategies interview questions with working code examples and real interview gotchas.

Practice Interactively →← All Categories
6 questions2 beginner3 core1 advanced
Q1Beginner

What is the Cache-Control header and what are its key directives?

💡 Hint: HTTP header that tells browsers and CDNs how long to cache a response — max-age, no-cache, no-store, immutable

Cache-Control is an HTTP response header that instructs browsers and intermediate caches (CDNs, proxies) how to store and serve a response.

Key directives:

  • max-age=N — cache the response for N seconds. After expiry the browser revalidates with the server.
  • s-maxage=N — like max-age but only for shared caches (CDNs). Overrides max-age for CDNs.
  • no-cache — don't serve from cache without revalidating with the server first (304 check). Despite the name, it does cache.
  • no-store — never cache. Used for sensitive data (banking, personal health).
  • immutable — tells the browser the resource will never change; don't revalidate even if max-age expires. Used with content-hashed filenames.
  • stale-while-revalidate=N — serve stale for up to N seconds while fetching a fresh copy in the background.
  • public — CDNs are allowed to cache. private — only the browser may cache (not CDNs).
# Content-hashed JS/CSS — cache forever, never revalidate
Cache-Control: public, max-age=31536000, immutable

# HTML — revalidate every request but serve stale instantly
Cache-Control: public, max-age=0, stale-while-revalidate=86400
Practice this question →
Q2Core

What is stale-while-revalidate and why is it a good default for HTML pages?

💡 Hint: Serve the cached (stale) response immediately while fetching fresh in the background — eliminates latency without sacrificing freshness

stale-while-revalidate (SWR) is a Cache-Control extension that says: "serve the cached version immediately (even if stale), but simultaneously fetch a fresh version in the background."

Without SWR: After max-age expires, the next request blocks waiting for the network — the user sees latency on every cache miss.

With SWR:

  1. First request within max-age → served instantly from cache.
  2. Request after max-age but within SWR window → served instantly from stale cache; background revalidation starts.
  3. Next request → gets the fresh version (background fetch completed).
Cache-Control: max-age=60, stale-while-revalidate=600
# Serve fresh for 60s; serve stale (but refresh) for 10 more minutes

Why good for HTML: HTML pages change infrequently enough that showing a 60-second-old version is fine for most users. Eliminates the "cache miss spike" at deploy time when all users hit the origin simultaneously.

React Query / SWR library: implements the same pattern at the data-fetching layer — show cached data immediately while refetching in the background.

Practice this question →
Q3Beginner

What is content-based cache busting and how does it work?

💡 Hint: Hash file contents and embed the hash in the filename — hash changes when content changes, so old URLs stay cached forever

Content-based cache busting includes a fingerprint of the file's content in its URL (filename or query param). The URL changes only when the file changes, allowing infinite cache lifetimes for unchanged files.

// Webpack/Vite output
main.a1b2c3d4.js  // hash changes when source changes
vendor.e5f6a7b8.js

// Cache-Control for hashed files
Cache-Control: public, max-age=31536000, immutable

How the browser update flow works:

  1. User's browser has main.a1b2c3d4.js cached for 1 year.
  2. You deploy a code change — the new file is main.x9y0z1w2.js.
  3. The updated HTML references the new filename — browser fetches it fresh.
  4. Old main.a1b2c3d4.js is simply never requested again (it expires naturally).

Key insight: The HTML file itself should have a short/no cache time (or use no-cache) because it's the entry point that references all hashed assets. If the HTML is stale, users get the old filenames.

Practice this question →
Q4Core

What caching strategies can a service worker implement?

💡 Hint: Cache-first, network-first, stale-while-revalidate, cache-only, network-only — each suits different resource types

A service worker intercepts network requests and can apply different caching strategies per resource type:

Cache-first — serve from cache, fall back to network. Best for: versioned static assets (JS, CSS, fonts). Users get instant loads; stale risk is low since filenames change on update.

Network-first — try network, fall back to cache if offline. Best for: API responses where freshness matters. If network is slow, the user waits.

Stale-while-revalidate — serve cache immediately, update cache from network in background. Best for: content that can tolerate being one refresh cycle stale (blog posts, product listings).

Cache-only — only serve from cache, never hit network. Best for: pre-cached app shells in offline-first PWAs.

Network-only — never use cache. Best for: analytics, payment requests where you must not serve stale data.

// Workbox helper (used by Next.js PWA plugin)
registerRoute(
  ({ request }) => request.destination === 'image',
  new CacheFirst({ cacheName: 'images', plugins: [new ExpirationPlugin({ maxEntries: 50 })] })
);
Practice this question →
Q5Core

What is ETags and conditional requests, and when does the browser use them?

💡 Hint: ETag is a fingerprint the server sends; browser sends If-None-Match on revalidation — 304 Not Modified skips re-downloading the body

An ETag (Entity Tag) is an opaque identifier the server assigns to a specific version of a resource.

// Server response
HTTP/1.1 200 OK
ETag: "abc123"
Cache-Control: no-cache
Content-Type: text/html

Revalidation flow:

  1. Browser stores the response with its ETag.
  2. On next request (after cache expires or with no-cache), browser sends: If-None-Match: "abc123"
  3. If content unchanged → server responds 304 Not Modified with no body — saves bandwidth.
  4. If content changed → server responds 200 OK with new content and new ETag.

Last-Modified / If-Modified-Since — older alternative using a timestamp instead of a hash. Less reliable (timestamps can be off).

When browsers use conditional requests:

  • When Cache-Control: no-cache is set (revalidate every time).
  • When max-age has expired.
  • When the user does a soft reload (F5 on Windows).
Practice this question →
Q6Advanced

What is cache invalidation and why is it considered hard?

💡 Hint: Knowing when a cached item is stale requires global coordination — the cache has no automatic knowledge that the source changed

Cache invalidation is the process of removing or marking stale cached entries when the underlying data changes. Phil Karlton famously said: "There are only two hard things in Computer Science: cache invalidation and naming things."

Why it's hard:

  • No automatic notification — the cache doesn't know the origin changed. You must explicitly tell it.
  • Distributed state — content may be cached in browsers (worldwide), CDN edge nodes (hundreds of PoPs), and application caches simultaneously. Purging all of them atomically is difficult.
  • Dependency chains — a product page cache depends on the product, its price, its stock level, and the user's locale. Any of those changing should invalidate the page, but tracking all dependencies is complex.
  • Stale reads — during the window between a data change and cache invalidation, some users see stale data.

Common patterns to manage it:

  • Content-hashed URLs — invalides automatically when content changes (no explicit purge needed).
  • Short TTLs — accept stale windows rather than trying to purge proactively.
  • CDN purge API — Cloudflare, Fastly provide tag-based purging (purge all edges caching a given tag).
  • Cache-Control: no-cache + ETag — always revalidate but serve from cache on 304.
Practice this question →

Other System-design Interview Topics

Rendering StrategiesCore JSType SystemReact FundamentalsFunctionsMicrofrontendsGenericsAsync JSHooksObjectsMonorepoArrays'this' KeywordUtility TypesError HandlingModern JSBundle OptimizationPerformanceDOM & EventsState ManagementClasses & OOPComponent PatternsAdvanced TypesAuthenticationReact RouterFormsAdvanced PatternsFrontend SecurityConcurrent ReactServer ComponentsTestingEcosystemNetwork OptimizationCore Web VitalsBrowser APIs

Ready to practice Caching Strategies?

Get AI feedback on your answers, predict code output, and fix real bugs.

Start Free Practice →