Cache Invalidation
Removing or updating stale cache entries when the underlying data changes. One of the two hard problems in computer science (along with naming things).
What is Cache Invalidation?
In short
Cache invalidation is the process of removing or updating cached copies of data once the original source changes, so readers stop getting stale results. It is the mechanism that keeps a fast cache consistent with the slower source of truth behind it.
What it actually means
A cache is a fast copy of data that lives closer to whoever needs it: in RAM, on a CDN edge node, or in a service like Redis. The whole point is to avoid asking the slow source (a database, an API, a disk) every single time. The problem starts the moment the source changes. The cached copy is now wrong, and anyone reading it gets old data.
Cache invalidation is how you deal with that. You either delete the stale entry so the next read fetches fresh data, or you overwrite it with the new value. Done well, users never notice the cache exists. Done badly, you serve a deleted product, an old price, or a profile photo someone changed an hour ago.
The reason it has a reputation as one of the hard problems in computer science is timing. The source and the cache live in different places, updates take time to propagate, and many readers hit the cache at once. Deciding exactly when an entry is no longer valid, and making sure every copy of it learns that, is genuinely tricky at scale.
How it works under the hood
There are three common strategies, and most systems mix them. The first is time based expiry, or TTL. You tag each entry with a lifetime, say 60 seconds, and the cache automatically drops it when the clock runs out. It is simple and needs no coordination, but it accepts staleness for the length of the TTL.
The second is explicit invalidation on write. When your application updates a record, it also deletes or updates the matching cache key in the same code path. A common pattern is cache-aside: the app reads from the cache, falls back to the database on a miss, and on any write it deletes the key so the next read repopulates it. Deleting is usually safer than updating in place because it avoids a race where two writers leave a wrong value behind.
The third is event based invalidation. Instead of every writer knowing about every cache, a change emits an event, often through a log like Kafka or a database change stream, and subscribers purge the affected keys. CDNs work this way too: you call a purge API and the edge nodes drop the cached object. This decouples the writer from the caches but adds propagation delay measured in milliseconds to seconds.
Key design is the quiet part that decides whether any of this works. If a single piece of data is cached under five different keys, all five have to be invalidated or you will leak stale copies. Many bugs are not in the invalidation logic itself but in forgetting which keys depend on a given record.
When to use it and the trade-offs
The core trade-off is consistency versus cost. Aggressive invalidation keeps data fresh but means more cache misses, more load on the database, and more complexity in your write path. Loose invalidation, like a long TTL, keeps the database quiet but serves older data. You pick based on how much staleness the feature can tolerate. A bank balance needs immediate invalidation. A list of trending articles can be a minute stale and nobody cares.
Two failure modes are worth naming. A thundering herd happens when a popular key expires and thousands of requests miss the cache at the same instant and all slam the database. You guard against it with request coalescing or a short lock so only one request rebuilds the entry. Stale reads happen when invalidation is delayed or dropped, so you may add versioning or a write-through cache where the write updates cache and database together.
A practical rule: prefer deleting keys over mutating them, give every entry some TTL as a safety net even when you also invalidate explicitly, and never trust that an event-based purge always arrives. Belt and suspenders is cheaper than a stale-data incident.
A concrete example
Picture an e-commerce product page. The price and stock count are cached in Redis under a key like product:1234, with a 5 minute TTL. Reads are fast and the database barely sees traffic.
An admin drops the price. The update writes to PostgreSQL, then in the same request deletes product:1234 from Redis. The very next visitor misses the cache, reads the fresh price from PostgreSQL, and the cache repopulates with the new value. Total staleness window: effectively zero.
But the product also appears on a category listing cached under category:electronics, and in a search results cache. Those keys still hold the old price. So the write path also has to invalidate them, or accept that they will fix themselves when their own TTL expires. This is the everyday reality of invalidation: the hard part is not deleting one key, it is knowing every place a piece of data was copied to.
Where it is used in production
Redis
The most common application cache. Apps delete or overwrite keys on write, and use TTLs as a backstop against missed invalidations.
Cloudflare
CDN caching with a purge API and cache tags so origins can invalidate edge copies of pages and assets on demand.
Its Memcache layer uses leases and a cache invalidation pipeline to keep thousands of cache servers in sync with the database after writes.
Varnish
HTTP reverse-proxy cache where stale content is purged or banned by URL pattern, widely used in front of news and media sites.
Frequently asked questions
- Why is cache invalidation considered so hard?
- Because the cache and the source of truth live in different places and update at different times, with many readers and writers hitting them at once. Knowing exactly when an entry is stale, and making sure every copy of it across servers or edge nodes learns that at roughly the same time, is a distributed timing problem with lots of edge cases.
- Should I delete the cache key or update it on a write?
- Usually delete it. Deleting lets the next read repopulate from the source, which sidesteps the race where two concurrent writers leave a wrong value in place. Updating in place is only safe when you fully control ordering, such as in a write-through cache that updates the cache and database atomically.
- What is the difference between a TTL and explicit invalidation?
- A TTL expires an entry automatically after a fixed time and needs no coordination, but it tolerates staleness for that whole window. Explicit invalidation removes the entry the instant the data changes, so it is fresher but requires the write path to know exactly which keys to clear. Most systems use both: explicit invalidation for correctness and a TTL as a safety net.
- What is a thundering herd and how do I avoid it?
- It happens when a popular cache key expires and many requests miss simultaneously, all hammering the database to rebuild the same value. You avoid it with request coalescing or a short lock so only one request recomputes the entry while the rest wait, and sometimes by refreshing hot keys slightly before they expire.
- Does cache invalidation guarantee my cache is always correct?
- No. Events can be dropped, purges can lag, and you can forget that data was cached under more than one key. Treat invalidation as best effort and add safety nets: give entries a TTL, version your keys when data changes shape, and design so a brief stale read is tolerable rather than catastrophic.
Learn Cache Invalidation hands-on
This page explains the idea. The full lesson lets you step through the ring as servers join and leave, read the implementation, and check yourself with a quiz. It is one of 760+ lessons in the System Design Masterclass, from your first API call to distributed consensus. Eleven Foundation lessons are free, no signup. Lifetime access is ₹499 in India or $7.99 worldwide, one payment, no subscription.
See also
Related glossary terms you might want to look up next.
Caching
Storing frequently accessed data in a faster storage layer so you don't have to fetch it from the original (slower) source every time.
TTL
Time To Live: how long a cached entry, DNS record, or packet is valid before it expires and must be refreshed or discarded.
Write-Through Cache
A caching pattern where every write goes to both the cache and the database simultaneously. Ensures consistency but adds write latency.
CDN
A network of servers distributed globally that caches content close to users. Netflix uses CDNs to stream video from servers near you, not from one central location.
Cache Eviction
The process of removing entries from a cache when it's full. Common policies: LRU (least recently used), LFU (least frequently used), FIFO (first in, first out).
Cache-Aside
A caching pattern where the application checks the cache first; on a miss, it fetches from the database and populates the cache. Also called lazy loading.