# A cache needs a freshness promise

Decide how old a value may be and what happens when that limit is exceeded. Faster reads are useful only while the result remains suitable for the task.

By Cobnex editorial. Published 2026-09-10. Updated 2026-09-11.

## Different screens can tolerate different delays

A public list of office locations may remain useful for several minutes after an edit. A permission decision or available credit check can become unsafe immediately after a change. Giving both the same cache duration makes a technical convenience into an accidental business policy.

Begin with the action the reader will take. A stock indication on a catalogue can be approximate if checkout validates availability. A dispatch operation needs the authoritative reservation decision. The acceptable age depends on where the information is used, not simply which database table stores it.

Document that distinction in the interface as well as the backend. If a screen presents a delayed estimate as a confirmed quantity, the user cannot make the right decision even when the cache behaves exactly as configured.

## Treat the cache as a copy

In a cache-aside arrangement, the application loads missing values from the source and stores them for later reads. The source remains responsible for the authoritative state. This simple pattern reduces repeated work, but it does not automatically keep every copy current.

Identify all copies involved. A browser, edge cache, application process and shared cache can each retain a response. Clearing one layer may leave another serving the old result.

### Freshness is checked before reuse

A cached result is usable only within the policy for the requested operation. Otherwise the application obtains an authoritative value.

1. **Request context**: Identify resource, tenant and required freshness
2. **Cached copy**: Check scope, version and allowed age
3. **Authoritative read**: Load current data when reuse is unsuitable
4. **Response**: Return the value with an appropriate freshness policy

## Understand the refill race

Suppose a reader loads revision 4 from the database. Before it stores that value in the cache, a writer commits revision 5 and deletes the cache entry. The reader then stores revision 4. Invalidation happened, yet stale data returned.

Deleting after the database commit avoids one common ordering mistake, but does not eliminate every concurrent race. Depending on the required guarantee, consider version checks, generation-based keys or bypassing the cache for critical reads. Each introduces its own coordination requirements.

A short expiry limits the duration of some stale values. It does not prove that a value is current at the moment a business decision is made.

## Choose behaviour during failure

When the source is unavailable, some information can be served stale with a clear age indicator. Other operations should wait or fail. Decide this per use case rather than enabling stale fallback across the entire application.

Protect the source from a sudden wave of misses. Coalescing concurrent loads, limiting refresh work and spreading expiry times can help, but test their behaviour when the cache is empty. A warm-cache benchmark hides the most demanding recovery condition.

The design is ready when a maintainer can explain what a reader sees after a write, during a failed invalidation and after a cache restart. A high hit rate alone answers none of those questions.

## Sources

- [Microsoft: cache-aside pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/cache-aside)
- [HTTP caching standard](https://www.rfc-editor.org/rfc/rfc9111.html)
