A cache can make repeat reads faster by serving a stored copy instead of querying the source of truth. The trade-off is that the copy can become outdated: a database update does not automatically update every cache, and concurrent reads, writes, or failed invalidations can leave stale data visible. The right design depends on the freshness contract your application needs—not on an assumption that every cached value must always be perfectly current.
Why can a cache return old data after a database update?
A cache adds another place where a value lives. When the source changes, the cached copy remains unchanged unless the application updates it, removes it, or lets it expire. Until then, a cache read can return the earlier value.
That gap is a consistency problem: different parts of the system can present different versions of what is logically the same data. With several application instances, each may have its own local cache; with a shared cache, the shared entry can still be stale. A cache does not become consistent merely because it is distributed.
The important question is how fresh a value must be for a particular operation. A profile page may tolerate an old value briefly, while a decision involving a balance, inventory, or permissions may require a read from the authoritative store. Martin Kleppmann’s discussion of web-app caching likewise emphasizes that acceptable staleness depends on the use case: Rethinking caching in web apps.
#1 Best Overall
How common cache strategies handle freshness
These patterns differ in when the cache is populated or updated, what a successful write means for later reads, and what the system must do when a step fails. AWS advises that “The patterns you choose to implement should be directly related to your caching and application objectives.” Its caching-pattern guidance and Redis’s cache-aside documentation describe common approaches.
| Strategy | How it works | Freshness and failure trade-offs | Best fit |
|---|---|---|---|
| Cache-aside (lazy loading) | The application checks the cache first. On a miss, it reads the source and stores the result. A write commonly updates the source and invalidates the corresponding cache key. | Demand-driven and flexible, but application code must coordinate the source and cache. Invalidation can be missed or race with a cache fill. Cold reads reach the source. | Repeated reads where some staleness is acceptable and the application can manage invalidation. |
| Write-through | The write path updates the source and cache synchronously. | When both updates succeed, subsequent cache reads can see the new value. If only one side succeeds, the application needs a recovery plan. Entries may be cached even if they are not read again. | Read-after-write behavior matters and the extra coordination on writes is acceptable. |
| Write-behind (write-back) | The cache accepts a write and persists it to the source asynchronously. | Can reduce work on the write path, but the source may remain behind. If the cache fails before persistence, an acknowledged change may be lost. | Write-heavy workloads where delayed persistence and its failure risk are acceptable. |
| TTL (expiry) | Each cached entry expires after a configured duration. | Expiration limits how long an entry can remain, but does not make reads immediately consistent after a write. Shorter TTLs can increase source reads and cache misses. | Data with a known tolerance for staleness and no stronger propagation requirement. |
| Invalidation or change propagation | A write or a stream of source changes deletes or refreshes affected cache entries. | Can reduce stale windows, but delivery, ordering, retries, replay, and key dependencies need to be handled. Writes that bypass the propagation path can still leave stale entries. | Stricter freshness needs when all relevant changes can be observed and propagated reliably. |
| Read from the primary or bypass the cache | For selected reads, the application goes directly to the authoritative store. | Avoids relying on a cache copy for that read, but gives up some cache latency or load benefits. A separate read replica may itself lag. | Critical decisions where stale data has a high cost. |
TTL is a limit on entry lifetime, not a promise of read-your-writes behavior. Set it according to how often the data changes and the consequences of serving an old value. AWS discusses TTL and invalidation as data-access design choices in its caching guidance and Redis database-caching whitepaper.
Rank #2
How a cache invalidation race reintroduces stale data
Deleting a key after a write is useful, but the timing matters. Consider a cache miss that overlaps a database update:
- An application instance misses the cache and reads value A from the database.
- A writer commits newer value B to the database and deletes the cache key.
- The original reader, still holding A, finishes its cache fill and stores A under that key.
- Later cache reads return A until another update, invalidation, or expiry removes it.
The invalidation did happen, but the older in-flight read repopulated the empty key afterward. Redis’s vendor documentation describes this kind of cache-fill interleaving and notes that a failed invalidation can also leave stale data in place: Cache consistency strategies. Applications that need to prevent this race may need version checks, ordered updates, or another coordination mechanism; simple deletion after every write is not a universal guarantee.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
Why external writers and multiple copies complicate consistency
Writers that bypass the cache path
Cache-aside only coordinates the reads and writes that use its application logic. If an administrator, batch job, or separate service updates the database without invalidating or refreshing the cache, the cached copy has no way to know it is obsolete. Change-data capture can expose source changes to cache consumers, but the application still needs reliable delivery, retries, ordering, and recovery. See Kleppmann’s overview of change data capture.
Local caches on separate application instances
Two processes can each hold a private copy of the same value and update or expire those copies at different times. A shared remote cache removes some duplication, but it does not by itself define how writes, invalidations, and concurrent fills are coordinated. Microsoft’s cache-aside guidance calls out stale data and the consistency challenges of local caches.
Rank #4
Read replicas are a separate source of lag
Even a cache miss can return an older value if the application reads from a lagging replica rather than the primary. That is a database-replication issue in addition to cache freshness. Google Cloud warns that Memorystore for Redis read replicas may not provide read-your-writes consistency: About read replicas. Choosing a shared cache or reading from a primary can address particular paths, but neither automatically resolves every consistency issue across the system.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Choose the freshness contract before choosing the cache pattern
Describe the requirement in terms of what users or downstream decisions may observe. “The cache should be consistent” is too vague to guide implementation; “after saving a profile, the same user must see their edit on the next read” is a testable contract.
Best Value
- Stale window: How old may a value be, and is that limit different for different operations?
- Read-your-writes: Must a user immediately see a change they just made, even if other readers can briefly see the prior value?
- Writers: Which services, jobs, or administrative tools can change the source, and how will each change reach the cache?
- Failure behavior: What should happen if the source update succeeds but the cache update fails, or if invalidation is delayed or lost?
- Load and memory: Can the source handle a burst of misses or many entries expiring together? Is it worth caching values that might never be read again?
- Operational complexity: Can the team support ordering, retries, replay, and the mapping from changed records to affected cache keys?
For high-consequence reads, bypassing the cache for that path may be simpler than trying to coordinate every copy tightly. For less sensitive data, cache-aside with an appropriate TTL may be a reasonable trade-off. In either case, verify the actual read path: a primary read, a replica read, a local cache, and a shared cache have different failure and freshness characteristics.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




