Search

Caching Strategies: Write-Through, Write-Back, and Cache-Aside

The short answer

Quick answer: A cache stores copies of data somewhere faster than the original source. The strategies differ in who keeps the cache and the database in step. With cache-aside, the application checks the cache, and on a miss reads the database and fills the cache itself. With read-through, the cache library does that loading for you. With write-through, every write goes to the cache and the database together, so the cache is always fresh. With write-back (also called write-behind), writes go to the cache first and reach the database later, which is fastest but can lose data. Most systems use cache-aside with expiry times.

Why cache

  • Speed. Memory is far faster than disk or a network call.
  • Load. Each cache hit is a query your database did not have to run.
  • Cost. Expensive computations and paid API calls are done once.

Caching works because access is uneven: a small share of the data receives most of the requests. Caches exist at every layer, from the browser to CDNs to the database's own memory. This article is about the application-level cache that sits between your code and your database, typically Redis or Memcached. See why Redis is fast.

Reading strategies

Cache-aside (lazy loading)

The application manages the cache directly.

def get_user(user_id):
    user = cache.get(f"user:{user_id}")
    if user is None:                        # miss
        user = db.query_user(user_id)
        cache.set(f"user:{user_id}", user, ttl=300)
    return user
  • Only requested data is cached.
  • Resilient: if the cache is down, the application can still read the database.
  • The first request is slow (a miss costs three steps).
  • Data can be stale until it expires or is invalidated.

On writes, the usual approach is to update the database and then delete the cache key, so the next read reloads it.

Read-through

The same flow, but the cache layer itself loads from the database on a miss. Application code only ever talks to the cache. It is tidier, at the cost of needing a cache library or service that supports loaders.

Refresh-ahead

The cache refreshes popular entries in the background shortly before they expire, so users rarely see a miss. It helps for hot keys but wastes work if predictions are wrong.

Writing strategies

Write-through

Every write updates the cache and the database as one operation, before returning.

  • The cache is never stale.
  • Writes are slower, since each does two operations.
  • Data that is never read is cached anyway. Add an expiry to clear it.

Write-through is usually paired with read-through or cache-aside for reads.

Write-back (write-behind)

The write goes to the cache and returns immediately. A background process writes to the database later, often in batches.

  • Very fast writes, and many updates to the same key collapse into one database write.
  • Risk of data loss: if the cache fails before flushing, those writes are gone.
  • The database lags, so anything reading it directly sees old data.

It suits high-volume, loss-tolerant data such as view counters, analytics and activity timestamps. It does not suit payments.

Write-around

Write only to the database and let reads populate the cache later. It avoids caching data nobody reads, but recently written data always causes a miss.

StrategyRead speedWrite speedFreshnessRisk
Cache-asideFast after the first missNormalCan be stale until TTL or invalidationLow
Read-throughFast after the first missNormalSame as cache-asideLow
Write-throughFastSlowerAlways freshLow
Write-backFastFastestDatabase lagsData loss if the cache fails
Write-aroundMiss after each writeNormalFresh on reloadLow

The AWS guide to caching patterns covers the same patterns with further detail.

Invalidation: the hard part

There is a well-known saying that the two hard things in computer science are cache invalidation and naming things. See why naming things is hard for the other half.

The difficulty is that the cache and the database are two separate systems with no shared transaction.

Time to live (TTL)

Give every entry an expiry. Stale data is tolerated for at most that long. It is simple and self-healing, and it should be your baseline even if you also invalidate explicitly.

Delete on write

After updating the database, delete the key. Deleting is safer than writing the new value into the cache, because two concurrent updates can write to the cache in the opposite order from the database and leave the wrong value there permanently.

Even delete-on-write has a race:

  1. Request A misses the cache and reads the old value from the database.
  2. Request B updates the database and deletes the cache key.
  3. Request A now writes the old value into the cache.

Mitigations include short TTLs, deleting again after a brief delay, or versioning entries. With read replicas, replication lag can produce the same effect.

Event-driven invalidation

Publish change events from the database (change data capture) and have a consumer invalidate or update cache entries. It keeps application code simple and catches changes made by any writer.

When the cache is full: eviction

A cache has limited memory, so it must discard something.

PolicyEvictsGood for
LRU (least recently used)The entry unused for longestGeneral purpose default
LFU (least frequently used)The entry used least oftenStable popularity patterns
FIFOThe oldest entrySimple cases
TTL-basedEntries closest to expiryTime-sensitive data
RandomAny entryVery low overhead

Failure modes

Cache stampede (thundering herd)

A popular key expires. Hundreds of requests miss at once and all run the same expensive query, which can overwhelm the database.

Fixes:

  • Locking: only one request recomputes; the others wait or serve the old value.
  • Stale-while-revalidate: serve the expired value while refreshing in the background.
  • Early refresh: refresh probabilistically before expiry.
  • TTL jitter: add randomness to expiry times so keys do not expire together.

Cache penetration

Requests for keys that do not exist miss the cache every time and always hit the database. Attackers exploit this. Cache the "not found" result briefly, or use a Bloom filter to reject impossible keys.

Cache avalanche

Many keys expire at once, or the cache server restarts empty. Stagger TTLs, warm the cache before taking traffic, and make sure the database can survive a cold cache.

Hot keys

One extremely popular key overloads a single cache node. Replicate it or add a small in-process cache in front.

Practical guidelines

  1. Measure first. Cache what is slow and frequently read.
  2. Start with cache-aside plus a TTL. It is simple and fails safely.
  3. Choose TTLs by tolerance for staleness, not by habit.
  4. Never treat the cache as the source of truth unless you have designed for its loss.
  5. Use clear, versioned key names, such as user:v2:42.
  6. Track the hit ratio. A low one means the cache is not earning its keep.
  7. Plan for the cache being unavailable.

Frequently asked questions

What is the difference between cache-aside and read-through?

In cache-aside, application code loads from the database on a miss and populates the cache. In read-through, the cache layer does it automatically.

What is the difference between write-through and write-back?

Write-through writes to the cache and the database before returning. Write-back writes to the cache and updates the database later, asynchronously.

How long should a cache TTL be?

As long as stale data is acceptable for that item. Seconds for fast-changing data, minutes or hours for slow-changing data.

Should I update or delete the cache entry after a write?

Deleting is usually safer. The next read reloads the correct value, and you avoid concurrent writers leaving an out-of-date value in the cache.

Conclusion

Caching trades freshness for speed, and each strategy places that trade differently. Cache-aside with a sensible TTL handles most cases. Write-through keeps data fresh at the cost of slower writes, and write-back buys speed with risk. Whichever you choose, the real work is invalidation and guarding against stampedes.

Related articles

Sources and further reading

Usama Muneer

Usama Muneer

Coder, Blogger, Tech Speaker & Web Technologies Enthusiast. Passionate about working on open-source Programming languages & Tools while utilizing my Product Development skills.

Your experience on this site will be improved by allowing cookies Cookie Policy