Cache Invalidation Strategies
Caching speeds up reads, but every cached value is a copy of data that lives somewhere else, and copies drift out of sync the moment the source changes. Invalidation is the discipline of deciding when a cached entry stops being trustworthy and what to do about it. Get it wrong and users see stale prices, outdated inventory counts, or old profile pictures; get it too aggressive and you erase the performance benefit of caching in the first place. There is no universally correct answer — the right strategy depends on how tolerant the application is of staleness, how often the underlying data changes, and how expensive a cache miss is.
Cricket analogy: A scoreboard operator who doesn't update the run count the instant a boundary is hit leaves fans watching a stale total; update too eagerly on every ball including no-ball reviews and you risk flashing wrong numbers before confirmation.
Time-to-Live (TTL) expiration
The simplest strategy attaches an expiration timestamp to every cached entry. Once the TTL elapses, the entry is treated as absent and the next read repopulates it from the source of truth. TTLs require no coordination between the writer and the cache, which makes them trivially easy to implement and reason about, but they trade correctness for simplicity: for up to the length of the TTL, readers may see data that no longer matches the database. Systems commonly use short TTLs (seconds) for volatile data like stock prices and long TTLs (hours or days) for near-static data like a country list.
Cricket analogy: A ground's electronic scoreboard that refreshes every 30 seconds regardless of what's happening needs no live coordination with the scorer's desk, but for half a minute after a wicket falls it can still show the wrong batter at the crease.
Write-through and write-behind caching
Write-through caching updates the cache synchronously as part of every write to the database, so the cache is never allowed to go stale in the first place — every write pays the extra latency of touching both stores. Write-behind (write-back) caching instead accepts the write into the cache immediately and asynchronously flushes it to the durable store later, which is fast but risks losing the update if the cache node crashes before the flush completes. Both patterns differ from TTL-based caching in that they proactively keep the cache correct rather than passively letting it expire.
Cricket analogy: Write-through is like a scorer who updates both the paper scorebook and the electronic board the instant a run is scored, guaranteeing they always match but slowing every single delivery slightly. Write-behind is like updating the paper scorebook instantly but only transcribing it to the official league database at the end of the over, faster ball-to-ball but risking a lost run if the scorer's notes are misplaced before transcription.
Explicit invalidation on write
A more precise approach deletes or updates the specific cache key the moment its underlying row changes, typically triggered from the application code or a database change-data-capture (CDC) stream. This minimizes the staleness window to essentially the propagation delay of the invalidation message, but it requires the write path to know every cache key that could be derived from the data it just changed — a non-trivial bookkeeping problem when the same row feeds multiple cached views (e.g. a user's profile cached both standalone and embedded inside a feed post).
Cricket analogy: Instead of waiting for the scoreboard's periodic refresh, the scorer directly overwrites just the 'current batter' field the instant a wicket falls — fast, but if that batter's average is also shown on three other panels around the ground, all three must be told, or one screen goes stale.
Write path with explicit invalidation:
Client -> App Server: UPDATE product(id=42).price
App Server -> Database: UPDATE products SET price=... WHERE id=42
App Server -> Cache: DEL product:42
App Server -> Cache: DEL product_list:category:shoes (derived view)
Next read:
Client -> App Server: GET product 42
App Server -> Cache: GET product:42 -> MISS
App Server -> Database: SELECT * FROM products WHERE id=42
App Server -> Cache: SET product:42 (value, TTL=300s)
App Server -> Client: fresh valueA classic bug is invalidating the primary cache key but forgetting derived or aggregate keys built from the same data (category listings, search indexes, denormalized counters). This is often called the 'cache invalidation is hard' trap, and it is one of the two famously hard problems in computer science alongside naming things and off-by-one errors.
Facebook's TAO caching layer combines write-through semantics for the primary object cache with asynchronous propagation to other data centers, accepting brief cross-region staleness in exchange for very low read latency in the region where the write occurred.
Choosing a strategy
In practice, teams blend approaches: TTLs act as a safety net that bounds worst-case staleness even if an explicit invalidation is missed, while explicit invalidation keeps the common case fast and fresh. The right mix depends on read/write ratio — read-heavy, write-rare data favors long TTLs with explicit invalidation on the rare write, while write-heavy data may not benefit from caching at all.
Cricket analogy: A club blends approaches: the scoreboard auto-refreshes every 30 seconds as a safety net even if the scorer forgets a manual update, while for high-stakes moments like a wicket, the scorer still pushes an immediate manual correction rather than waiting for the timer.
- TTL-based expiration is simple and requires no write-path coordination but allows bounded staleness.
- Write-through keeps the cache always correct at the cost of extra write latency on every request.
- Write-behind is fast but risks data loss if the cache fails before flushing to durable storage.
- Explicit invalidation on write minimizes staleness but must account for every derived/aggregate cache key.
- Combining a TTL safety net with explicit invalidation is a common, pragmatic middle ground.
- The right strategy depends on the read/write ratio and how tolerant the application is of stale reads.
Practice what you learned
1. Which invalidation approach guarantees the cache is never stale, at the cost of added write latency?
2. What is the main risk of write-behind (write-back) caching?
3. Why is explicit invalidation on write considered error-prone in practice?
4. What role does a TTL play when combined with explicit invalidation?
5. For which type of data is caching typically least beneficial?
Was this page helpful?
You May Also Like
Why Caching Matters
Explains the core motivation for caching in system design — reducing latency and load by storing frequently accessed data closer to where it's needed.
Cache Eviction Policies
Covers the algorithms caches use to decide what to remove when full, comparing LRU, LFU, FIFO, and TTL-based approaches and their tradeoffs.
CDN Caching and Edge Computing
Covers how Content Delivery Networks cache content close to users to cut latency, and how edge computing extends this to running logic near the request origin.
Database Replication
Explains how copying data across multiple database nodes improves read throughput and fault tolerance, and the consistency tradeoffs of leader-follower and multi-leader setups.
Related Reading
Related Study Notes in Software Engineering
Browse all study notesMicroservices Study Notes
Software Architecture · 30 topics
Software EngineeringTesting & TDD Study Notes
Software Testing · 30 topics
Software EngineeringDesign Patterns Study Notes
Software Design · 30 topics
Software EngineeringSoftware Engineering Study Notes
Python · 40 topics
Software EngineeringGit & Version Control Study Notes
Bash · 40 topics