
Caching is the cheapest performance win available and the easiest to get subtly wrong. The two failure modes are serving data that should have changed, and a cache that collapses precisely when traffic peaks.
Cache by change rate and cost
The best candidates are expensive to compute and rarely change: reference data, computed aggregates, rendered pages for anonymous visitors, embeddings of stable documents. Cheap and constantly changing data is the worst candidate — you add complexity and staleness risk for a saving you cannot measure.
Cache what is expensive and stable. Everything else is complexity shopping.
Layers, and what belongs in each
A CDN handles anything identical for all anonymous users and is by far the biggest win for content sites. A shared cache such as Redis holds computed results across instances. In-process memory is fastest but per-instance, so it suits small, hot, rarely-changing lookups only.
Prefer expiry to invalidation
Explicit invalidation requires knowing every place a piece of data is cached, which is exactly the knowledge that decays as a system grows. A short TTL is less precise and dramatically more robust. Reach for explicit invalidation only where staleness is genuinely unacceptable, and accept that it is now a maintenance obligation.
The stampede
A popular key expires and a thousand concurrent requests all miss, all hit the database, and the database falls over. This happens at peak traffic, because that is when there are a thousand concurrent requests. Mitigate with a lock so one request recomputes while others wait or serve stale, and jitter your TTLs so keys do not expire in unison.
Cache keys must include everything
A key omitting the tenant, the locale or the user's permissions will eventually serve one customer's data to another. This is a security incident, not a bug. Build keys deliberately from every input that changes the output, and review them as carefully as you review an authorisation check.
Measure the hit rate or do not bother
A cache with a 20% hit rate is complexity you are paying for and not benefiting from. Instrument hit rate per cache and per key pattern; low rates usually mean the TTL is too short, the key is too specific, or the data was never a good candidate.





