This series has covered cache-aside, read-through and write-through, TTL, eviction, invalidation, stampedes, distributed caching, Redis, local caching, CDNs, edge caching, and scaling. But the question that actually matters when you sit down to design a system is simpler than any of that: what should I cache, where should I cache it, how long should I keep it, and what happens if the cached value is wrong?
There's no single answer. Let's walk through real scenarios and see how the answer changes each time.
1. E-commerce product catalog
A store with 10 million products, all getting hit with GET /products/12345 repeatedly. Thousands of users requesting the same product is exactly the shape caching exists for — one database query can serve all of them through Redis.
But should every field on that product be cached the same way? A description and an image rarely change; a rating changes periodically; a price can change often; inventory changes constantly. Treating all of them identically wastes the opportunity that caching offers — the strategy should follow each field's actual volatility, not a single TTL applied to the whole object.
2. Inventory is a different animal entirely
"Only 1 left!" and two customers clicking "buy" at nearly the same instant is exactly the scenario where a cached inventory count can sell something that's no longer there. That's a materially different kind of wrong than a stale product description — one is cosmetic, the other loses money and trust. A common answer: cache the product information normally, but keep inventory tied to an authoritative source, or use a very short-lived cache combined with an authoritative check at the actual moment of checkout. Not all data on the same object deserves the same consistency guarantee.
3. Banking customer profile
GET /customer/profile doesn't change often, which makes it look cacheable — but it's private, personalized, and potentially sensitive, so it can never casually land in a shared CDN cache the way a product image could. A private cache keyed by identity — customer:12345:profile — keeps one customer's data from ever being served to another. This is the Part 12 public/private distinction showing up with real stakes attached.
4. Account balance is where caching should back off
GET /account/balance is the sharper version of the same problem. A stale product description is mildly annoying. A stale balance showing $10,500 when the real number is $10,000 is a different category of wrong entirely. This is often a case for going straight to an authoritative service rather than aggressively caching — caching isn't automatically good just because something is read frequently. Correctness comes first, and for this kind of data, it isn't a close call.
5. Social media feed — precompute instead of cache-on-request
A feed is expensive to generate, requested constantly, personalized, and constantly changing — a genuinely hard caching problem, because the usual "compute once, serve many times" logic doesn't hold when the result is different for every user. The answer often isn't caching after the fact — it's precomputing before anyone asks: a new post triggers fan-out processing that updates a feed cache directly, so a user's request reads an already-assembled result instead of triggering a live rebuild.
6. The precompute pattern, generalized
The general version of that idea: instead of "store the result after someone asks for it," it's "calculate the result before anyone asks." Trending products recalculated every five minutes and written to Redis means 100,000 users read the same precomputed value instead of triggering the computation 100,000 times. This pattern earns its keep for leaderboards, trending content, recommendations, reports, dashboards, and aggregated statistics — anywhere the expensive part can happen once, on a schedule, ahead of demand.
7. Search results — repetition matters more than volume
Search is expensive, but many users searching "wireless headphones" means genuine repetition exists to exploit — cache the result, and check the cache before hitting the search engine on a miss.
8. Cache key explosion is the trap hiding behind that idea
Search results depend on query, filters, sorting, pagination, and sometimes location or personalization — combine enough of those dimensions and the number of distinct cache keys can explode into millions of low-value entries that are each requested once and never again. Before caching search results, it's worth actually asking how often the exact same query repeats. If nearly every query is unique, caching provides close to nothing — the infrastructure cost without the benefit.
9. Configuration — one of the best caching candidates that exists
Feature flags, application settings, supported countries, UI configuration: read constantly, changed rarely. This is about as clean a caching candidate as exists, and it's worth loading at application startup directly into memory rather than hitting Redis on every request — thousands of requests can then be served from a local copy without a network call at all.
10. But configuration has a real invalidation problem
If enableNewPaymentFlow flips from false to true and application instances refresh their local copies at different times, some instances run the new flow while others run the old one simultaneously — genuinely inconsistent behavior across a fleet that's supposedly running the same code. Event-driven refresh, the pattern from Part 5, is the common fix: a configuration-changed event fans out to every instance, and each one refreshes its local cache on receipt rather than waiting for its own independent TTL to expire.
11. Session data
session:abc123 holding user ID, login state, preferences, and expiration is the classic reason to keep sessions in a shared store like Redis rather than pinned to one application server — any instance behind the load balancer can serve any user's session, which is what makes horizontal scaling behind a load balancer actually work cleanly.
12. API response caching — sometimes the CDN is simply the right layer
GET /api/countries changes once every few weeks but gets hit constantly. Public, shared, relatively static, and naturally an HTTP response — that's the CDN's exact sweet spot from Part 12, and routing this through Redis instead would be solving a problem the CDN already solves for free.
13. Images and static content — the easiest call in this entire post
Images, CSS, JavaScript, fonts, video: a CDN is the obvious answer, and the application doesn't need to participate in serving any of it. This is a large part of how modern web architectures serve enormous traffic volumes without correspondingly enormous application-server fleets.
14. Expensive computation, not just expensive database reads
Caching isn't only for database results. If calculateCustomerRisk() takes 800ms and the underlying inputs only change hourly, caching the result of the computation — not a database row — is exactly as valid a caching decision. The same logic applies to recommendation scores, ML predictions, pricing calculations, analytics, reports, and complex business rules: anywhere the expensive part is CPU time rather than a database round trip.
15. Caching a specific query result, not a whole object
Sometimes what's worth caching isn't a business object at all but one specific expensive query — SELECT COUNT(*) FROM orders WHERE customer_id = 12345 cached as customer:12345:order-count. The invalidation question shows up immediately: every new order changes the answer, so either invalidate on order creation or deliberately accept some staleness. Which one is right depends entirely on how much that count is allowed to lag reality.
16. Rate limiting isn't caching, but it's the same muscle
Tracking user:12345:requests against a 100-requests-per-minute limit via a Redis counter isn't "cache the database result" in the traditional sense — there's no database result being cached at all. It's worth including here anyway, because it demonstrates something broader: a fast, shared, in-memory store solves problems well beyond caching once it exists in your architecture.
17. Feature flags, and designing the fallback deliberately
isNewCheckoutEnabled() checked hundreds of times a second shouldn't hit a remote configuration service on every call — a local cache refreshed periodically gives low latency, resilience, and less network traffic. The question worth asking explicitly: what happens if the cached flag value is wrong? For some flags the safe default is off; for others it's on. That fallback behavior needs to be a deliberate choice per flag, not an accident of whatever the cache happened to return.
18. Recommendations tolerate more staleness than they get credit for
A recommendation engine combining user history, the product catalog, an ML model, and business rules can easily take hundreds of milliseconds to compute. Caching recommendations:user:12345 for five minutes (or longer) raises a genuinely useful question: does a recommendation actually need to change every second? Usually not — and once that's acknowledged, a five-minute-old recommendation stops looking like a compromise and starts looking like the obviously correct design.
19. Stock market data — one domain, four completely different strategies
AAPL isn't one caching decision — it's at least four. The live price genuinely shouldn't be cached at all; it belongs in a streaming system built for continuous updates. Historical prices are effectively immutable once recorded, so they cache indefinitely. Company information changes maybe once a year and can sit in a long-lived cache. News needs a short TTL measured in minutes, not hours. Same ticker symbol, four different answers to "how should this be cached" — because the question was never really about the ticker, it was about each piece of data behind it.
The real question, restated
Every scenario above resolves to the same underlying question, and it's worth seeing them plotted against it directly rather than as a list.
Access frequency tells you whether caching would help. Staleness tolerance tells you whether it's safe. Those are different questions, and a data type can score high on the first and low on the second — account balances are read constantly, which says nothing about how safe they are to cache.
A framework for the decision itself
Before caching anything, it's worth running through this in order:
A "no" on being frequently read, or a "no" on being expensive to retrieve, just means caching wouldn't help much — a mild missed opportunity at worst. A "no" on tolerating staleness is a different kind of answer entirely: it means caching could make the system actively wrong, not just occasionally slow, and the better move is going to the authoritative source directly rather than trying to cache carefully around the problem.
Don't forget the failure path
Every design above has a HIT path and a MISS path. Production also needs a defined answer for what happens when the cache itself is unavailable — Redis ERROR needs its own branch, not an assumption that it collapses into MISS behavior automatically. We'll go deeper on this specific failure mode next.
One application, many strategies at once
The biggest practical lesson across every scenario above: there's no requirement to standardize on one mechanism company-wide.
Different data has different requirements, and using a different mechanism for each is completely normal — not a sign the architecture is inconsistent, but a sign it's actually matched to the problem in each case.
The architect's actual starting question
Not "should we use Redis?" — that question skips past everything that determines the right answer. The better starting point: which requests are expensive, repetitive, and safe to serve from a cached representation? From there: what's the data, how often is it read, how often does it change, how stale can it safely be, who's allowed to see it, where should it live, how does it get invalidated, and what happens when the cache fails? That sequence, worked through deliberately, is a far stronger design process than picking a technology first and looking for places to apply it.
The bigger lesson
A product catalog, a bank balance, an image, a session, a recommendation, a search result, and a stock price can all legitimately need completely different caching approaches — and that's not a failure to standardize, it's the correct outcome of actually looking at each one. The question was never "can I cache this?" It's "what happens if I serve an old value?" If the honest answer is "nothing important," that's very likely a great caching candidate. If the honest answer is "we could lose money, expose private data, or make an incorrect business decision," caching needs far more careful design — or, in some cases, shouldn't be used there at all.
Which of these scenarios hits closest to something you've actually built — and did the staleness question get asked before or after something went wrong in production?
















