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:
- Memory cache (in-memory variables, JavaScript objects)
- HTTP cache (browser cache, controlled by headers)
- Service Worker cache (programmatically controlled)
- 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 hourCache-Control: no-cache— always revalidateCache-Control: immutable— never revalidateETag: "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:
- Memory cache (TanStack Query) — instant if cached
- Service Worker cache — fast if cached
- HTTP cache (browser) — fast if cached, may revalidate
- CDN edge — fast for cacheable assets
- 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.