When should you NOT reach for a cache? What are the real risks of over-caching?
Caching is often sold as a free performance win, but every cache you add is a second source of truth, a new failure mode, and a bet that staleness is cheaper than the query you're avoiding.
LEARN BY DOINGPut your intuition to work3 steps
When should you NOT reach for a cache? What are the real risks of over-caching?
Use the lesson’s examples and explanation to check your idea.
Personal reflection. Nothing is sent to an AI service.#Caching is a trade, not a free win
Every cache is a bet: that serving slightly stale, duplicated data is cheaper than computing or fetching the fresh version every time. That bet is often correct — but it's still a bet, and interviewers ask this question specifically to see whether a candidate treats caching as a default reflex or as a deliberate trade-off with real costs on the other side of the ledger. The honest answer to "should I cache this?" is "not automatically," and knowing when to say no is as senior a skill as knowing how to build the cache in the first place.
#The real risks of over-caching
Stale data becomes a correctness bug, not just a UX nuisance. A five-second-old product description is harmless. A five-second-old account balance that lets a withdrawal go through against funds that were already spent elsewhere is a financial incident. Inventory counts during checkout, permission/role checks, feature flags that gate a kill switch, and anything feeding a financial ledger are all places where "eventually consistent" is the wrong consistency model, and a cache silently converts your system from strongly consistent to eventually consistent without anyone deciding that on purpose.
Debugging gets harder, not easier. A cache adds a second source of truth that can disagree with the first one, and disagreements are, by construction, invisible in the normal request path — the request still returns 200 OK, just with the wrong body. "It works after I restart the service" and "it's fine in staging but wrong in prod" are both classic symptoms of a cache that's out of sync with the database, and neither shows up in a stack trace. Every cache you add is also indirection a future engineer has to learn before they can trust what a function actually returns.
It's frequently premature optimization. Caching a query that already runs in two milliseconds because it's backed by a proper index doesn't make the system faster in any way a user can feel — it just adds a new component to run, monitor, and eventually debug, in exchange for shaving latency nobody was going to notice. The right sequence is: measure the actual latency and call volume of the operation, confirm it's actually a bottleneck, and only then reach for a cache — not the other way around.
A cache can hide a bug instead of fixing one. A page that's slow because it fires 200 unbatched queries per request (a classic N+1) will indeed get faster if you cache its output — but you've cached the symptom. The underlying query pattern is still bad, it'll resurface the moment the cache is cold or invalidated, and now there are two problems to fix instead of one.
Operational surface grows. A cache is infrastructure: something to provision, scale, secure, and keep available. When it goes down, you don't just lose the speed-up — you can get a "cache stampede" (also called thundering herd or dog-piling), where every request that used to hit the cache now hits the database simultaneously, at a volume the database was never sized for, turning a cache outage into a database outage.
Invalidation complexity compounds. Every additional cached query is another entry in the invalidation map: another set of write paths that now need to remember to bust the right keys. This grows faster than linearly, because writes rarely map to just one cached query — and a missed invalidation path is a bug that only manifests as "sometimes the data is wrong," which is one of the hardest categories of bug to reproduce and fix.
#When NOT to reach for a cache
| Situation | Why caching hurts more than it helps |
|---|---|
| Strict consistency is required (balances, inventory at checkout, auth decisions) | Staleness isn't a performance trade here, it's a correctness violation |
| The data is read once or rarely (a one-off report, a per-session computation) | Hit rate stays near zero, so the cache adds overhead without ever paying it back |
| The underlying operation is already fast | There's no latency to reclaim; the cache is pure added complexity |
| The write:read ratio is high | You'll be invalidating almost as often as you'd otherwise be querying — no net win |
| You can't articulate a clear invalidation rule | If you can't say what busts the cache, you will ship a stale-data bug, not an optimization |
| The real problem is a missing index or a bad query shape | Caching hides the symptom and lets the actual defect ship to production |
#A lighter mitigation worth knowing
Even when caching is the right call, over-caching creeps in through the mitigations themselves if they're applied everywhere by default. Techniques like request coalescing (only one request per key is allowed to go compute the value while others wait for it) or stale-while-revalidate (serve the old value immediately while refreshing it in the background) exist specifically to fight cache stampedes and staleness windows — but reaching for them on every cache, rather than the ones that actually see contention or tight consistency requirements, is the same premature-optimization mistake one layer up.
🧠 Check your understanding
0/2 · 0/2 answered1. A cache is added in front of a report that two internal users view about once per week. What's the most likely outcome?
2. Which of these is the strongest argument for NOT caching a value?