How it works
Start with the data and its freshness requirement. Cache reusable, expensive reads such as a short code's destination, a restaurant summary, or a weather forecast. Define keys that include every input affecting the result, including tenant, permissions scope, filters, and data version where needed. Choose the layer deliberately: an in-process cache avoids network calls but creates separate copies; a shared cache supports many application servers; a CDN caches HTTP responses near users.
With cache-aside, the application checks the cache first. On a miss, it reads the database, stores the result with a time to live (TTL), and returns it. For example, GET link:abc misses, so the service loads the destination from the database and caches it. On updates, a common approach is to commit the database change and then invalidate the cached entry. Read-through has a similar read path, but the cache layer handles loading rather than application code.
With write-through, the write path synchronously updates the backing store and cache before reporting success. Compared with cache-aside, this can keep newly written data ready for reads, but adds write latency and requires a policy for partial failures. A database write and a cache write are not automatically atomic; concurrent writers can still install older values unless updates are coordinated or version-checked. Write-around writes only to the database and invalidates any existing entry, leaving later reads to populate the cache.
With write-behind, also called write-back, writes reach the cache first and are persisted asynchronously. This can reduce foreground write latency and combine repeated updates, but makes the buffered writes part of the durability story. Define whether acknowledgment requires a durable log, how retries preserve order, and what happens when the buffer fills. It is a poor default for authoritative balances or inventory unless durability and correctness are explicitly designed.
Control freshness with expiration, invalidation, or refresh. TTL limits how long an entry remains eligible to serve after insertion; it does not automatically bound source-data staleness. A slow reader can fetch an old database value, race with an update and invalidation, then repopulate stale data. Version checks, coordinated fills and invalidations, or a fresh authoritative read may be needed. Stale-while-revalidate serves an expired-but-allowed value while one worker refreshes it, so its maximum stale window must be explicit.
Plan for misses and bounded memory. Use an eviction policy such as LRU or LFU, and distinguish capacity eviction from TTL expiration. Coalesce concurrent loads for the same key, add TTL jitter to spread expirations across keys, and consider short-lived negative caching for missing records. During cache failures, use short timeouts, bounded fallback concurrency, and load shedding rather than sending every request to the database.
A worked example
Cache-aside for a URL shortener
Assume a URL shortener receives 100,000 redirects per second and achieves a 95% cache hit rate. Its steady-state database read load is about 5,000 reads per second, excluding retries and other traffic. Use cache-aside for short-code mappings with a five-minute TTL and jitter. Coalesce simultaneous misses for the same code, and cache missing codes briefly to reduce repeated invalid lookups. After changing a destination, commit the database update and invalidate the entry; handle stale-fill races if edits require a strict freshness deadline. A cache outage could expose all 100,000 reads per second to the database, so cap fallback concurrency and reject excess requests rather than assuming the database can absorb them.
Trade-offs to say out loud
- Lower read cost versus stale results
- Longer TTLs improve reuse but allow older data to remain visible unless updates trigger reliable invalidation or refresh.
- Cache-aside simplicity versus cold misses
- Cache-aside loads only requested data, but the first reader pays the database cost and concurrent misses can amplify load.
- Write-through readiness versus write coupling
- Synchronously updating the cache makes written values available sooner, but adds latency and requires explicit handling of partial failures and concurrent writes.
- Write-behind speed versus durability complexity
- Acknowledging before persistence can reduce latency, but requires durable buffering, ordered replay, and backpressure if losing acknowledged updates is unacceptable.
- Local speed versus shared consistency
- In-process caches avoid network overhead but duplicate memory and make invalidation harder across application instances.
- High hit rate versus failure capacity
- A cache can hide an undersized database, so a cold start or outage still needs admission control rather than unlimited fallback traffic.
When to reach for it
- Repeated reads target a reusable working set, such as popular links, restaurant pages, or document revisions.
- An expensive database query, external API call, or computation sits on a latency-sensitive request path.
- Read traffic is much higher than update traffic, and the product can define an acceptable freshness window.
- A few hot objects dominate traffic and need local caching, shared caching, or CDN delivery rather than more database shards.
- Different data classes need different policies, such as immutable media with long retention and mutable account state with strict freshness.
How to bring it up in the interview
- Name the cached object, key, layer, and source of truth before naming a technology: 'Cache public restaurant summaries by restaurant ID; keep review writes in the database.'
- State a freshness requirement and choose a strategy around it: 'Cache-aside with a short TTL is enough for display ratings, but checkout rechecks authoritative inventory.'
- Estimate database load as read QPS × miss rate, then separately discuss cold starts, expensive misses, and uneven key popularity; interviewers often probe whether the database survives a cache outage.
- Walk through one concurrent read and update, including a reader repopulating stale data after invalidation; be ready to explain version checks, invalidation delivery, or when to bypass caching.
- Defend the failure policy and measurements: bounded fallback, stale serving only where allowed, hit rate by workload, miss latency, evictions, hot-key load, and invalidation lag.
Common mistakes
- Saying 'add Redis' without specifying what is cached, how it is populated, or how changes reach readers.
- Claiming write-through makes cache and database updates atomic, or that deleting a cache entry after a write eliminates all stale-read races.
- Treating TTL as a guaranteed bound on source freshness while ignoring stale fills, lagging replicas, and stale-while-revalidate behavior.
- Using a favorable average hit rate to ignore synchronized expiration, a single hot key, or an unavailable cache.
- Caching personalized or permission-sensitive responses under incomplete keys, or assuming a long-lived cached response remains authorized after access is revoked.
Where it comes up
Interview questions where caching strategies is part of a strong answer, and why.
- Design a URL shortener like BitlyRedirect traffic makes cache-aside reads, hot-code handling, and invalidation after destination changes central design decisions.
- Design a news feed like FacebookFeed caches require explicit choices about population, asynchronous updates, pagination, and freshness after new posts.
- Design a distributed cacheEviction, TTL semantics, hot keys, and miss amplification define the behavior of the cache itself.
- Design a weather appGeographic reuse, forecast versions, and stale serving during upstream outages require a deliberate caching and freshness policy.
- Design Wikipedia or NotionGlobal page caching must distinguish immutable revisions from mutable page pointers and preserve access control.
- Design a restaurant review app like YelpHot restaurant pages need reusable cached summaries without hiding review edits or serving indefinitely stale ratings.
- Design an ETA and live location sharing serviceReusing route and ETA computations requires cache keys and freshness rules that account for movement and changing traffic.
- Design an ads serving systemLow-latency ad selection depends on cached campaign data while campaign changes and budget enforcement require separate correctness rules.
Questions people ask
What is the difference between cache-aside and write-through?
Cache-aside lets the application load data into the cache when a read misses; updates usually write to the database and invalidate cached data. Write-through synchronously updates the backing store and cache on the write path. Cache-aside avoids populating unread data, while write-through adds write work and still needs a partial-failure and concurrency policy.
How do you choose a cache TTL?
Start with how stale the product allows the data to be, then consider update frequency, miss cost, and memory pressure. Use different TTLs for different data classes and add jitter to avoid many keys expiring together. A TTL alone does not guarantee source freshness if fills read old data or race with updates.
How do you prevent a cache stampede?
Coalesce concurrent misses so only one loader per key fetches from the source within the coordination scope; per-process coalescing still allows one loader per application instance. Use TTL jitter for expirations across many keys, and stale-while-revalidate where older data is acceptable. Also bound source requests, because coalescing a hot key does not protect against a flood of distinct misses.