Frontend Caching Strategies: HTTP, Memory, IndexedDB

Caching is one of the most effective ways to make a frontend feel fast. It is also one of the most error-prone. The interview probes whether you understand the multiple cache layers in a browser, when to use each, and the bugs caching introduces.

The cache layers

From most ephemeral to most persistent:

  1. Memory cache (in-memory variables, JavaScript objects)
  2. HTTP cache (browser cache, controlled by headers)
  3. Service Worker cache (programmatically controlled)
  4. IndexedDB / localStorage (persistent, app-controlled)

Memory cache

JavaScript objects. Lifecycle: page load → page unload.

Use for:

  • Server response data within a session
  • Computed values that are expensive to recompute
  • UI state derived from server data

Tools: TanStack Query, SWR, Apollo all manage memory cache for server state. Don’t reinvent.

HTTP cache

Browser-managed cache controlled by HTTP headers:

  • Cache-Control: max-age=3600 — fresh for 1 hour
  • Cache-Control: no-cache — always revalidate
  • Cache-Control: immutable — never revalidate
  • ETag: "abc123" — fingerprint for conditional requests

Use for static assets (JS, CSS, images, fonts) and rarely-changing API responses.

Cache-busting

For static assets that may change:

  • Hash in filename: app.abc123.js
  • Long max-age + immutable
  • HTML references the hashed URL
  • HTML itself has short cache to pick up new asset URLs

This is the “fingerprinted assets + short HTML cache” pattern. Universal in modern frontend.

Service Worker cache

Programmatic cache via the Cache API. Use for offline support and custom caching policies.

Strategies:

  • Cache-first: static assets that rarely change
  • Network-first: API responses that need freshness
  • Stale-while-revalidate: good UX with eventual consistency

IndexedDB

Persistent client-side database. Use for:

  • Offline-first apps with significant data
  • Local content that survives browser restart
  • Caching API responses for cold-start performance

API is callback-heavy and awkward. Wrappers help: idb (Jake Archibald), Dexie.js.

localStorage / sessionStorage

Synchronous, small (5–10 MB). Avoid for:

  • Sensitive data (XSS-readable)
  • Large data (slow synchronous I/O)

Use for:

  • User preferences (theme, language)
  • Lightweight session state
  • Tracking opt-outs / consent flags

Cache invalidation

The hard part. Strategies:

  • Time-based: max-age expires
  • ETag: conditional revalidation
  • Version-based: bump cache key on app version change
  • Push-based: server signals invalidation (rare in HTTP)

Combine: time-based for freshness; version-based for code changes.

Cache hierarchy in practice

Typical request flow:

  1. Memory cache (TanStack Query) — instant if cached
  2. Service Worker cache — fast if cached
  3. HTTP cache (browser) — fast if cached, may revalidate
  4. CDN edge — fast for cacheable assets
  5. Origin server — slow but authoritative

Each layer is faster than the next. Hit the highest layer that has the data.

Cache stampede

When cache expires, many concurrent requests hit the origin simultaneously. Mitigations:

  • Stale-while-revalidate: serve stale, refresh in background
  • Request coalescing: deduplicate concurrent requests for the same key
  • Backend cache layer (Redis) absorbs the burst

Cache poisoning

Caching wrong data can be hard to fix. Causes:

  • Cache responses that vary by user without proper Vary headers
  • Cache personalized content as public
  • Cache error responses (negative cache without TTL)

Be deliberate about what you cache.

Common mistakes

  • No HTTP caching on static assets
  • Caching API responses that have user-specific data publicly
  • Forgetting to bust cache on app updates
  • Caching everything in localStorage (slow, blocking)
  • Service Worker caching old versions of HTML

Frequently Asked Questions

How do I cache an authenticated API response safely?

Use Cache-Control private, with proper Vary on Authorization header. Or skip HTTP cache; use memory cache only.

Should I use Service Worker for caching?

For PWAs: yes. For typical web apps: HTTP cache + memory cache is sufficient. Service Worker adds complexity.

How do I handle a user with stale cached HTML?

Short HTML cache (5 min max). Cache asset URLs are hashed; new HTML pulls new asset URLs. The combo is reliable.

Scroll to Top