Caching strategies for system design interviews, explained
Almost every system design interview reaches a moment where the database is the bottleneck and someone says "add a cache" — and that is where the real question starts. Caching strategies are not one idea; they are a set of deliberate choices about where a copy of the data lives, who loads it, when it is written, and what happens when it goes stale, and an interviewer can tell in thirty seconds whether you have a vocabulary for those choices or whether "add a cache" is where your thinking stops. A cache trades a little memory and a lot of correctness-anxiety for latency and database offload, and the whole skill is knowing exactly which trade you are making.
The reason this comes up in almost every round is that caching sits on the two axes every design cares about: latency and load. A read served from memory is orders of magnitude faster than one that touches disk, and every read the cache absorbs is one the database never sees. But a cache is a second copy of the truth, and the instant you have two copies you own a consistency problem — the data can be stale, two writers can race, and a key everyone wants can expire at the worst possible moment. This guide walks the choices a strong candidate names out loud: the read strategies (cache-aside and read-through), the write strategies (write-through, write-back and write-around), the eviction policy that decides what to throw away, and the three failures — invalidation, the thundering-herd stampede, and hot keys — that the follow-up questions are really about.
Why caching strategies come up in system design interviews
Caching rarely gets its own whiteboard prompt. It shows up inside another design — a news feed, a product catalogue, a rate limiter, a URL shortener — at the moment you realise the read volume will crush the database. You draw a box labelled "cache," and the interviewer leans in: not whether to cache, but how. Which strategy, what you cache, how you keep it honest, and what happens the moment it fails. Caching is a favourite probe precisely because "add a cache" is the easy half of the sentence and everything true and hard lives in the second half.
The interviewer rarely lets "we'll cache it" stand on its own. "You cache a user's profile, then they update their email. The next read still serves the old address from cache. Walk me through exactly what happened on the write, and what you'd change so the cache and the database don't disagree." That question — consistency between two copies of the truth — is the one a memorised "use Redis" answer can never survive, and the one this topic is really testing.
The rounds on Zynter are modelled on how the loop runs, not scraped from any candidate's recall. What matters for prep is the shape: you name a strategy, and the next sentence out of the interviewer's mouth attacks its weakest point — staleness, write latency, a dropped write, or a stampede.
What the interviewer is really testing
A caching answer is read on the same four dimensions as any design decision. Problem solving — did you pick a strategy that fits the read/write mix, or reach for the first one you remember? Communication — can you say in one sentence why cache-aside tolerates a cache outage but write-back risks losing data? Technical execution — do you handle invalidation on writes, and do you have a concrete fix for a hot key expiring under load? Time management — did you spend your words on the consistency and failure story, not on reciting that Redis is in-memory? Reading this guide teaches the strategies; it does not teach you to defend one while someone pushes on the stale read.
Read strategies: cache-aside and read-through
Start with reads, because that is where a cache earns its keep. The question a read strategy answers is: who is responsible for loading data into the cache on a miss — your application, or the cache itself?
Cache-aside (lazy loading) is the default and the one to reach for first. The application talks to both the cache and the database and owns the logic:
- On a read, check the cache. On a hit, return it. On a miss, read from the database, write the value into the cache, and return it.
- Only data that is actually requested is ever cached — the cache stays populated with the working set, nothing wasted.
- It is resilient: if the cache is down, the application just reads the database and keeps serving. The cache is an optimisation, not a dependency.
Its costs are the two you must name out loud: the first read of any key is always a miss (a cold cache means one slow request per key), and because the application writes the cache separately from the database, the two can drift out of sync unless you invalidate on writes. Cache-aside is what most systems use because the failure mode is graceful — a stale or cold cache degrades latency, not correctness.
Read-through moves the loading logic into the cache layer. The application only ever talks to the cache; on a miss the cache itself fetches from the database, stores the value, and returns it.
- The application code is simpler — one place to read from, no miss-handling branch.
- The load logic lives in the cache (or a library in front of it), so it is consistent across every caller.
- But the cache is now a hard dependency in the read path, and the first-read-miss latency still exists — it just moved.
Say the distinction crisply: cache-aside puts the application in charge and survives a cache outage; read-through hides the database behind the cache for simpler code but makes the cache load-bearing. For most interview designs, cache-aside is the safe default — reach for read-through when you want the loading logic centralised and can accept the cache as a dependency.
Write strategies: write-through, write-back and write-around
Reads decide how the cache fills; writes decide whether it ever lies. The follow-up here is the sharp one — you have the data in two places now; on a write, how do you keep them from disagreeing, and what are you willing to lose? Each strategy answers differently, and the difference is a trade between write latency, consistency, and durability.
Write-through — write the cache and the database together, synchronously, as part of the same operation. The cache is always consistent with the database, so a read right after a write is correct. The cost is write latency: every write pays for both stores, and you may cache data that is never read again.
Write-back (write-behind) — write only the cache, acknowledge immediately, and flush to the database asynchronously (batched, after a delay). Writes are very fast and the database sees far less write load because writes are coalesced. The danger you must state plainly: if the cache node fails before the flush, those writes are lost — this is a durability risk, acceptable for metrics or counters, dangerous for a payment.
Write-around — write straight to the database and skip the cache; the cache fills only later, on a read (via cache-aside). This avoids flooding the cache with data that is written once and rarely read, but a read immediately after a write is a guaranteed miss.
| Strategy | On a write | Consistency | Write latency | Risk / best for |
|---|---|---|---|---|
| Write-through | cache and DB, synchronously | strong — cache matches DB | higher (two writes) | caches write-once-read-never data; safe default when reads follow writes |
| Write-back | cache now, DB async later | eventual — DB lags the cache | lowest | data loss if the cache dies before flush; best for high-write, loss-tolerant data (counters, metrics) |
| Write-around | DB only; cache fills on read | DB is the truth; cache may be cold | normal DB write | read-after-write is a miss; best for write-heavy data read rarely |
The sentence that scores: write-through buys consistency with write latency, write-back buys speed by risking durability, and write-around keeps write-once data out of the cache — so I'd pair cache-aside reads with write-through for a profile a user edits and reads back, and only reach for write-back where losing a few recent writes is acceptable. Naming the pairing — a read strategy and a write strategy together — is what separates a real answer from "use Redis."
System Design
HLD · Core concept
Pick and defend a caching strategy out loud
Eviction and the hard problems: invalidation, stampede and hot keys
A cache is finite, so you cannot keep everything — and the moment data lives in two places, keeping them honest becomes the hard part. This section is where most of the follow-ups land, because it is where caches break in production.
Eviction policy decides what to drop when the cache is full. Name the common ones and when each fits:
- LRU (least recently used) — evict what has not been touched longest. The sensible default: recently used data is likely to be used again.
- LFU (least frequently used) — evict what is accessed least often. Better when popularity is stable over time, but it clings to old favourites and is costlier to track.
- FIFO — evict the oldest inserted, regardless of use. Simple, rarely the best fit.
- TTL (time to live) — expire entries after a fixed age. Orthogonal to the above and almost always used with them: TTL bounds staleness, LRU bounds size.
Then the three failures the interviewer will push on:
- Cache invalidation — the famous hard problem: when the database changes, the cache must not keep serving the old value. The options are to invalidate (delete the key on write, so the next read re-loads it) or update the cache on write (write-through). Deletion is simpler and the usual choice; the trap is the read-modify race, where a stale read repopulates the cache just after a write deleted it. Short TTLs are the backstop that bounds how long any staleness can last.
- Cache stampede (thundering herd) — a single very popular key expires, and in the same instant thousands of concurrent requests all miss, all hit the database, and all try to recompute the same value — a self-inflicted load spike that can take the database down. The fixes to name: request coalescing (a lock or single-flight so only one request recomputes while the rest wait for the result), staggered TTLs with jitter (so hot keys do not all expire together), stale-while-revalidate (serve the slightly stale value while one request refreshes it in the background), and pre-warming keys you know will be hot.
- Hot keys — one key (a celebrity's profile, a viral post) draws so much traffic it overwhelms the single cache node holding it. The fixes: replicate the hot key across nodes, add a tiny local in-process cache in front of the shared cache, or shard the key's value.
The point to state plainly: eviction keeps the cache small, TTL keeps it fresh, invalidation keeps it honest, and coalescing keeps a miss from becoming an outage. Those are four different jobs and a strong answer names which one each mechanism does.
System Design
HLD · Core concept
Defend your invalidation and stampede plan out loud
Where caches live: a layered view
"Add a cache" is ambiguous until you say which cache, because caching happens at every layer between the user and the database, and a strong answer places its cache deliberately:
- Client / browser cache — the response never leaves the user's device; the cheapest hit of all, controlled by cache headers. Best for static, user-specific data.
- CDN / edge cache — static assets and cacheable responses served from a point of presence near the user; absorbs read traffic before it reaches your servers at all.
- Application / distributed cache — a shared in-memory store like Redis or Memcached sitting between the app servers and the database. This is the cache most interview discussions mean: it holds the hot working set, is shared across app instances, and is where cache-aside and write-through play out.
- Database cache — the database's own buffer pool and query cache. Real, but not something you design; mention it, do not lean on it.
The useful framing: traffic should be absorbed as early as possible — a request served from the browser or CDN is one your application and database never pay for. The distributed cache catches what gets through. Naming the layer you mean, rather than a generic "cache" box, is a small signal that reads as experience.
How to talk about caching in an interview
The probes from every section rhyme. Master these five and you can defend a caching decision in any design, not just this checklist.
- "You've added a cache — cache-aside or read-through, and why?" → Cache-aside by default: the app owns the miss logic and the system survives a cache outage because it can still read the database; read-through when I want the load logic centralised and can accept the cache as a dependency. (problem solving)
- "On a write, how do you keep the cache and database consistent?" → Invalidate the key on write (delete it so the next read re-loads), or use write-through to update both synchronously; back it with a short TTL so any missed invalidation self-heals, and watch for the read-modify race that repopulates stale data. (communication)
- "Write-through, write-back or write-around here?" → Write-through for data read back soon after a write (consistency worth the latency); write-back only where speed matters and losing a few recent writes is acceptable; write-around for write-once, rarely-read data. (technical execution)
- "A hot key expires and thousands of reads hit the database at once — what happens?" → A stampede that can take the database down; prevent it with request coalescing so one request recomputes while others wait, staggered TTLs with jitter, and stale-while-revalidate. (technical execution)
- "The cache is full — what gets evicted?" → LRU as the default, LFU when popularity is stable, with a TTL layered on to bound staleness regardless of the eviction policy. (problem solving)
Each maps to a debrief dimension. Reading them teaches the answers; it does not teach you to deliver them while someone interrupts with the stale read — that only comes from saying them out loud.
How to prepare: a short plan
You do not need a new topic for every design. You need the caching vocabulary automatic, so when a design hits its read bottleneck you reach for the right pair without thinking.
- Day 1: Learn the read strategies (cache-aside vs read-through) and the write strategies (write-through, write-back, write-around) until you can draw each flow and state its one-sentence trade-off from memory.
- Day 2: Drill the failures — invalidation on writes, the thundering-herd stampede and its four fixes, and hot keys. These are where the follow-ups live.
- Day 3: Place caching inside a real design (a feed, a catalogue, a URL shortener): pick a read strategy and a write strategy together, choose an eviction policy and TTL, and name the layer. Then do it out loud, timed, with someone pushing on the stale read and the hot key.
This explainer feeds the broader Top 25 system design interview questions — caching is a decision inside almost every one of them, so getting it automatic pays off across the whole list.
Frequently asked questions
What is the cache-aside (lazy loading) strategy?
Cache-aside is the most common caching pattern, where the application manages the cache directly. On a read, the application first checks the cache; on a hit it returns the cached value, and on a miss it reads from the database, writes that value into the cache, and returns it. Only data that is actually requested ever gets cached, so the cache naturally holds the working set. Its main advantages are resilience — if the cache goes down, the application simply reads from the database and keeps serving — and efficiency. Its costs are that the first read of any key is always a miss, and that the application must invalidate or update the cache on writes, or the two copies drift out of sync.
Cache-aside vs write-through — what's the difference?
They answer different questions, so they are often used together rather than being alternatives. Cache-aside is a read strategy: it decides how the cache gets populated on a miss (the application loads it). Write-through is a write strategy: it decides what happens on a write (update the cache and the database synchronously so they stay consistent). A very common real-world combination is cache-aside for reads plus write-through or explicit invalidation on writes, so reads are fast and lazily populated while writes keep the cache honest. Confusing the two — treating them as competing options — is a common interview slip.
What is write-back (write-behind) caching and when is it risky?
Write-back caching writes data to the cache and acknowledges the write immediately, then flushes it to the database asynchronously, usually batched after a short delay. This makes writes very fast and greatly reduces write load on the database, because many writes to the same key can be coalesced into one. The risk is durability: if the cache node fails before the pending writes are flushed to the database, those writes are lost permanently. That makes write-back a good fit for high-volume, loss-tolerant data such as counters, metrics or view counts, and a poor fit for data you cannot afford to lose, such as a payment or an order.
How do you handle cache invalidation?
Cache invalidation keeps the cache from serving stale data after the database changes. The two main approaches are to delete the key on a write — so the next read misses and re-loads the fresh value from the database — or to update the cache on the write, as write-through does. Deletion is simpler and the more common choice. A short time-to-live (TTL) is almost always used as a backstop, so that even if an invalidation is missed, any staleness is bounded to the TTL window. The subtle trap is the read-modify race, where a concurrent stale read repopulates the cache just after a write deleted the key; short TTLs and careful ordering reduce its impact.
What is a cache stampede and how do you prevent it?
A cache stampede, or thundering herd, happens when a single popular key expires and thousands of concurrent requests all miss at the same instant, all hit the database, and all try to recompute the same value at once — a self-inflicted load spike that can overwhelm the database. The standard preventions are request coalescing (a lock or single-flight mechanism so only one request recomputes the value while the others wait for the result), staggering TTLs with random jitter so hot keys do not all expire together, serving the slightly stale value while one request refreshes it in the background (stale-while-revalidate), and pre-warming keys you know will be hot before they are needed.
How do I practise a system design interview out loud?
Reading about caching strategies is not the same as defending one while an interviewer pushes on the stale read. On Zynter, the HLD track runs live voice rounds modelled on how real system design loops run — you talk through a design on a shared canvas, and a voice interviewer follows up one question at a time ("on a write, how do the cache and database stay consistent?", "a hot key expires — what happens?"), then gives you a debrief on problem solving, communication, technical execution and time management. The score is a practice signal, not a hiring decision.
Practise it on Zynter
You can recite cache-aside and write-through. The round is won on defending the stale read out loud.
Pick an HLD system design round, add your cache to the design on the canvas, and defend it out loud to a voice interviewer that keeps asking "on a write, how do the cache and database stay consistent?" and "a hot key just expired and ten thousand reads hit the database — what happens?" — then read the debrief. Zynter.ai is on-demand mock interviews modelled on real company loops, with 150+ rounds across 20 companies including the HLD system design track (Sep 2026).
Practise an HLD system design round →
Browse all interview tracks




Top comments (0)