PerformanceWeb APIsMedium

How does caching improve performance?

01

The Short Answer

Caching stores copies of data or computed results closer to where they're needed, so future requests can be served faster without repeating expensive operations. On the web, caching happens at multiple layers — browser memory, HTTP cache, CDN edge nodes, application-level caches, and database query caches. Each layer trades freshness for speed, and the art is choosing the right cache strategy for each type of data.

02

Layers of Caching

A single web request can hit multiple cache layers before reaching the origin server. Each layer is progressively further from the user but closer to the source of truth. A cache hit at any layer short-circuits the rest of the chain.

  • Browser memory cache
    • In-memory, fastest, cleared on tab close
    • Stores decoded images, parsed scripts, fetch responses
  • Browser disk cache (HTTP cache)
    • Persists across sessions, controlled by Cache-Control headers
    • Stores full HTTP responses keyed by URL
  • Service Worker cache
    • Programmable cache you control via Cache API
    • Enables offline support and custom caching strategies
  • CDN / Edge cache
    • Geographically distributed, serves static assets near the user
    • Reduces latency and origin server load
  • Application cache (Redis, Memcached)
    • Server-side, caches computed results or database queries
    • Avoids repeated expensive computations
  • Database query cache
    • Database-level caching of query results
    • Transparent to the application layer
03

HTTP Caching Headers

The browser's HTTP cache is controlled by response headers from the server. These headers tell the browser how long to keep a response, whether to revalidate before using it, and whether intermediate caches (CDNs, proxies) can store it.

cache-headers.txttext
# Cache for 1 year (immutable static assets with hashed filenames)
Cache-Control: public, max-age=31536000, immutable

# Cache for 5 minutes, then revalidate with server
Cache-Control: public, max-age=300, must-revalidate

# Don't cache at all (sensitive data, real-time content)
Cache-Control: no-store

# Cache but always revalidate before using (API responses)
Cache-Control: no-cache
# (confusing nameit DOES cache, but checks freshness every time)

# ETag for conditional requests (revalidation)
ETag: "abc123"
# Browser sends: If-None-Match: "abc123"
# Server responds: 304 Not Modified (use cached version)

The most effective pattern for static assets: use content-hashed filenames (app.a1b2c3.js) with max-age=31536000, immutable. The hash changes when the file changes, so the browser caches forever and gets a new URL when there's an update. No revalidation needed.

04

Caching Strategies

Different types of data need different caching strategies. The right strategy depends on how often the data changes, how critical freshness is, and how expensive it is to regenerate.

StrategyHow it worksBest for
Cache-firstServe from cache, only fetch if cache missStatic assets, fonts, images
Network-firstTry network, fall back to cache on failureAPI data that should be fresh but work offline
Stale-while-revalidateServe stale cache immediately, refetch in backgroundData that's OK slightly stale (user profiles, feeds)
Network-onlyAlways fetch from network, never cacheReal-time data (stock prices, live scores)
Cache-onlyOnly serve from cache, never fetchPre-cached offline content
05

Frontend Caching Patterns

Beyond HTTP caching, frontend applications implement their own caching layers. React Query and SWR maintain an in-memory cache of API responses. Memoization caches computed values. These application-level caches give you fine-grained control over freshness and invalidation.

frontend-caching.tstypescript
// React Query: automatic caching + stale-while-revalidate
const { data } = useQuery({
  queryKey: ['user', userId],
  queryFn: fetchUser,
  staleTime: 5 * 60 * 1000,    // Fresh for 5 min (no refetch)
  gcTime: 30 * 60 * 1000,       // Keep in cache for 30 min
});

// Manual memoization for expensive computations
const expensiveResult = useMemo(() => {
  return heavyComputation(data);
}, [data]);

// Simple in-memory cache for repeated function calls
const cache = new Map<string, Response>();

async function cachedFetch(url: string): Promise<Response> {
  if (cache.has(url)) return cache.get(url)!;
  const response = await fetch(url);
  cache.set(url, response.clone());
  return response;
}
06

Cache Invalidation

The hardest part of caching is knowing when to throw away stale data. Serve stale data too long and users see outdated content. Invalidate too aggressively and you lose the performance benefit. There are several approaches to invalidation, each with tradeoffs.

  • Time-based (TTL)
    • Cache expires after a fixed duration
    • Simple but can serve stale data until expiry
  • Event-based
    • Invalidate when a mutation happens (user updates profile → clear profile cache)
    • Precise but requires tracking dependencies
  • Version-based
    • Content-hashed URLs (app.abc123.js) — new content = new URL
    • Perfect for static assets, not applicable to API data
  • Conditional revalidation
    • ETag / Last-Modified — ask server if cache is still valid
    • Saves bandwidth (304 response has no body) but still requires a round-trip

The two hard problems in CS

"There are only two hard things in Computer Science: cache invalidation and naming things." — Phil Karlton. Cache invalidation is genuinely difficult because you're balancing performance (serve fast) against correctness (serve fresh). There's no universal solution — the right approach depends on your data's update frequency and tolerance for staleness.

07

Why Interviewers Ask This

This question tests your understanding of web performance optimization at multiple levels. Interviewers want to see that you know the different cache layers (browser, CDN, server), understand HTTP cache headers and what they control, can choose appropriate strategies for different data types, and appreciate the cache invalidation challenge. It shows you think about performance holistically — not just code optimization but infrastructure and network-level improvements.

Quick Revision Cheat Sheet

Cache layers: Browser memory → HTTP disk cache → Service Worker → CDN → Server cache

Static assets: Content-hashed filenames + max-age=31536000, immutable

API responses: no-cache (always revalidate) or short max-age + stale-while-revalidate

Sensitive data: no-store — never cache

SWR pattern: Show stale data instantly, refetch in background, update when fresh

Invalidation: TTL, event-based, version-based, or conditional (ETag/304)