Caching strategies on one cheat sheet
A cache is a bet. You're wagering that something you just spent time computing or fetching will be wanted again soon, and that keeping a copy somewhere fast is cheaper than doing the work twice. Most of the difficulty in caching isn't the copy — it's deciding when the bet stops paying.
Read strategies: how data gets into the cache
Cache-aside (also called lazy loading) is the one most applications use. The app asks the cache first; on a miss it reads the database, hands the answer back, and writes it into the cache on the way out. It's simple and the cache never holds anything nobody asked for. The costs are that every first request is a miss, and the app owns all the cache logic itself.
Read-through moves that logic into the cache. The app only ever talks to the cache; on a miss, the cache fetches from the database itself and stores the result. Cleaner application code, but it needs a cache layer that supports it.
Refresh-ahead refreshes popular entries before they expire, so a hot key never makes a user wait for a reload. It's the right call for a small set of frequently-read keys, and wasted work on everything else.
Write strategies: how the cache stays in step
Write-through writes to the cache and the database together, synchronously. The cache is never stale, and you pay for that on every write.
Write-behind (write-back) writes to the cache and queues the database write to happen asynchronously. Writes get very fast and bursts get absorbed — but if the cache dies before the queue drains, those writes are gone. Only worth it when you can tolerate that.
Write-around skips the cache entirely and writes straight to the database. Good for data that's written often and read rarely, since it stops one-off writes from evicting things people are actually reading. The tradeoff is that the first read after a write is always a miss.
Eviction: what leaves when it's full
A cache is small on purpose, so something has to go.
- LRU — least recently used. The sensible default, and a good match for most real access patterns.
- LFU — least frequently used. Better when popularity is stable, worse when it shifts, because yesterday's hits keep out today's.
- FIFO — oldest out first, regardless of use. Cheap, rarely what you want.
TTL is a different thing that often gets lumped in: it's expiry by clock, not by memory pressure. Eviction answers "we're full, who leaves?"; TTL answers "how long do we trust this?" Most systems use both.
The three ways it goes wrong
Stale data. The database moved on and the cache didn't. Either expire on a timer and accept a window of wrongness, or explicitly invalidate the key on write and accept the extra bookkeeping. There's a well-worn line, usually attributed to Phil Karlton, that the two hard problems in computer science are cache invalidation and naming things — it survives because it's true.
Cache stampede. A popular key expires, and every request that wanted it misses at the same instant and piles onto the database together. Three fixes, often combined: let only one request recompute while the others wait (single-flight), add random jitter to TTLs so keys don't expire in lockstep, and refresh hot keys slightly early.
Cold cache. After a deploy or a restart there's nothing in there, and the database takes the full load until it fills. If that's more than your database can absorb, warm the cache before sending traffic to the instance.
Choosing, roughly
Start with cache-aside plus a TTL, because it's the easiest to reason about and covers most read-heavy workloads. Add explicit invalidation when a stale read would actually hurt someone. Reach for write-behind only when write throughput is the real bottleneck and you've decided what you can afford to lose. And before adding a cache at all, check that the thing you're caching is genuinely slow — a cache in front of a fast query is a second source of truth you now have to keep honest.
The takeaway
Every caching decision is the same trade in a different costume: speed now against the risk of being wrong later. Pick the read and write strategies that match how your data is actually used, decide deliberately how long you're willing to be stale, and plan for the moment the cache is empty or everyone misses at once.
This explainer was made with LineLapse — type a topic, get a hand-drawn video. Make your own →