A cache answers a wonderfully sneaky question.

Instead of computing the truth right now, would you accept something that was true recently?

Most of the time the answer is yes. That is why the web is usable. Images arrive from nearby edges, database rows avoid repeated work, and the same expensive model response does not need to be rediscovered for identical input.

Then somebody changes a price, revokes a permission, or pays an invoice, and “recently” becomes the most important word in the system.

A fast answer from the past

Teams often talk about caches as boxes: browser cache, CDN cache, Redis cache, application cache. I find it more useful to think about clocks. Each layer keeps a version of reality from some earlier moment. The system's behavior depends on which clock answers first.

A page may combine a fresh account balance, a five-minute-old customer record, and a permissions object cached until logout. The UI presents one clean screen. Underneath, it is a group photo taken at different times.

Freshness is a product decision

The HTTP caching standard, RFC 9111, contains a vocabulary for freshness, validation, staleness, and cache control. The vocabulary is technical, but the decisions are product decisions.

A weather forecast can be ten minutes old. A seat map during checkout probably cannot. A profile photo may be stale for a day; an access revocation should travel faster than the person who was revoked.

“Cache for performance” is incomplete. Cache what, for how long, underwhich identity, and with what consequence if stale?

Invalidation is plural

The famous joke says cache invalidation is one of the hard problems. The joke undersells it. There is rarely one invalidation. A write may need to expire a list, a detail view, an aggregate, a search result, and an authorization decision living in different systems.

Prefer designs where correctness does not require remembering every derivative key. Version cache keys. Attach cached values to an explicit data version. Use short lifetimes for sensitive facts. Revalidate on actions whose cost of staleness is high.

Label time explicitly

Observability should record cache age, hit source, key version, and why an entry was considered valid. Otherwise a stale-data incident looks exactly like the database lied.

Sometimes the interface should show time too: “updated 12 minutes ago” is better than a crisp number pretending to be live. Honesty about freshness lets users make their own trade-off.

Every cache serves the past. Reliable systems simply decide, deliberately, how much past each part of the product can tolerate.

Further reading: RFC 9111: HTTP Caching.