Dev Skills

Cache write strategies: write-through, write-back, write-around and cache-aside

When data changes, who updates the cache, who updates the database, and in what order. Each answer has a different failure.

By devskills editorial team · Last updated

1

What problem do cache write strategies solve?

A cache holds a copy of data that lives in a database. Reads are the easy half. The hard half is writes: when a value changes, the cache and the database must be updated in some order, by someone, and every choice leaves a different window where they disagree or where data can be lost.

Interviewers ask "write-through or write-back?" to see whether you know what each costs when something crashes halfway. The names matter less than being able to say what a user sees in that window.

2

What cache write strategies cost you

What it costs you
Every strategy picks two of three: fast writes, a cache that is never stale, and no risk of losing a write. Write-through gives fresh data and safety but every write waits on both systems. Write-back gives fast writes and fresh reads but loses whatever was not yet flushed when the cache dies. Write-around and cache-aside keep writes simple and safe, and pay with misses and stale windows.
3

When to reach for cache write strategies, and when not to

Use it when

  • Cache-aside with delete-on-write: the default for read-heavy application data, such as profiles, products and settings.
  • Write-through: data that is read straight after it is written, where a stale read would confuse the user.
  • Write-back: very high write rates where losing the last second or two is acceptable, such as counters, metrics and presence.
  • Write-around: data written once and rarely read soon after, such as logs, uploads and audit records.

Do not, when

  • Write-back for money, orders or anything you cannot recompute. A cache crash becomes data loss.
  • Write-through for data that is mostly written and rarely read. You pay twice per write to cache things nobody asks for.
  • Any strategy for a value a commit decision depends on, such as remaining stock. Read that from the database inside the transaction.
4

How cache write strategies actually work

WriteCacheconfirms nowDatabasewritten later
the user is told it worked as soon as the cache has it — fastthe database catches up afterwards, so a crash in that gap loses the write
Write-back: the write is confirmed as soon as the cache has it, and reaches the database later. Fast, and anything not yet flushed is lost if the cache dies.

Two of these names describe the read path and three describe the write path, which is why the comparison confuses people. Cache-aside (also called lazy loading) and read-through say what happens on a read miss. Write-through, write-back (also called write-behind) and write-around say what happens on a write. A real system picks one of each. The most common pairing is cache-aside reads with delete-on-write.

Cache-aside. The application checks the cache; on a miss it reads the database, puts the value in the cache with a TTL, and returns it. On a write it updates the database and then deletes the cache key, so the next read reloads it. The cache only ever holds data someone asked for, and if the cache is down the application still works, just slower.

Read-through. Same behaviour, but the cache layer loads from the database itself, so application code only ever talks to the cache. It is tidier, and it ties the cache to your database schema.

Write-through. Every write goes to the cache and the database together, and returns only when both have it. Reads after a write are fresh. Write latency is the sum of both, and you cache everything written whether or not anyone reads it, which is why it is often paired with a TTL.

Write-back. The write goes to the cache and returns at once; the cache writes to the database later, often batching many updates to one key into one write. That is the fastest option and it absorbs bursts. The cost is the window: if the cache node dies before flushing, those writes are gone, and if the flush fails, the database falls behind silently. Use it only where the data can be lost or rebuilt, or where the cache itself is replicated and persisted.

Write-around. The write goes straight to the database and skips the cache (usually deleting any cached copy). The cache fills only when something is read. It suits write-heavy data that is rarely read back soon, and keeps one-off writes from pushing useful entries out of the cache.

The race that bites cache-aside. Reader A misses and reads the old value from the database. Writer B updates the database and deletes the key. Reader A, slow, now writes its old value into the cache. The cache is stale until the TTL expires, and nothing errors. Defences, cheapest first: keep a TTL on every key as a safety net; delete after the transaction commits, never before; delete a second time a short moment later ("delayed double delete"); or use leases, where the cache hands a token to the first reader on a miss and rejects its fill if the key was deleted in the meantime. Facebook's memcache paper describes leases for exactly this race.

Order matters in write-through too. Write the cache first and the database second, and a database failure leaves the cache holding a value that was never stored. Write the database first, then update or delete the cache; if the cache step fails, the TTL limits the damage.

Choosing by read/write ratio. Mostly reads with occasional writes: cache-aside plus delete-on-write plus a TTL. Reads right after writes, where a stale read is visible: write-through. Huge write volume to a few hot keys, where some loss is fine: write-back. Many writes that are rarely read: write-around.

PolicyPathWho writes the databaseStale readsWrite latencyCan lose writes?
Cache-aside (lazy loading)ReadThe applicationUntil delete or TTL; a race can extend itDatabase onlyNo
Read-throughReadThe application, or the cache librarySame as cache-asideDepends on the write policyNo
Write-throughWriteThe cache layer, synchronouslyRareCache + databaseNo
Write-back (write-behind)WriteThe cache, laterNone from the cache; the database lagsCache onlyYes, anything not yet flushed
Write-aroundWriteThe application, directlyFirst read after a write is a missDatabase onlyNo
The five policies. Read policy and write policy are separate choices, so most systems combine two of these rows.
cache-aside in Go — read path and write path
func (s *Store) GetUser(ctx context.Context, id int64) (User, error) {
key := fmt.Sprintf("user:%d", id)
if u, ok := s.cache.Get(ctx, key); ok {
return u, nil // hit
}
u, err := s.db.LoadUser(ctx, id) // miss: go to the source of truth
if err != nil {
return User{}, err
}
s.cache.Set(ctx, key, u, 10*time.Minute) // TTL is the safety net
return u, nil
}
func (s *Store) RenameUser(ctx context.Context, id int64, name string) error {
if err := s.db.UpdateName(ctx, id, name); err != nil { // database first
return err
}
// then invalidate, after the commit; if this fails, the TTL caps the damage
s.cache.Delete(ctx, fmt.Sprintf("user:%d", id))
return nil
}
Deleting rather than setting the new value on write avoids two writers racing to set different values. The next reader loads whatever the database holds.
UserCacheemptyDatabase
miss — now the database does the workanswer back, and the cache keeps a copy
Cache-aside on the read path: miss, read the database, fill the cache. The write path decides how long that filled value stays correct.
Common trap
  • Writing the cache before the database. A failed database write leaves a value in the cache that was never saved.
  • Calling write-back "write-through with batching" and skipping the data-loss window.
  • Cache-aside with no TTL. One missed delete and the stale value lives forever.
  • Treating read-through and write-through as competitors. One is a read policy and one is a write policy.
Say this
"Cache-aside reads, delete-on-write after commit, ten-minute TTL as a backstop. Cost: a narrow race can leave a stale value until the TTL, which is fine for a profile page. For the view counter I would use write-back, batching increments in memory and flushing every second, and say that a crash loses about a second of views."
5

The follow-up an interviewer will ask about cache write strategies

"You use cache-aside and delete the key after every update. A user still saw an old value for ten minutes. How?"

What a strong answer sounds like

The classic read-write race. A reader missed the cache and read the row from the database just before a writer updated it. The writer committed and deleted the key. Then the reader, which was slow, wrote the old row into the cache, after the delete. Nothing failed, so nothing logged it, and the old value lived until its ten-minute TTL. I would check first that the delete happens after the commit, because deleting before commit opens the same window wider. Then, depending on how much a stale read hurts: shorten the TTL for this kind of data, add a second delete a second or so after the write, or use leases so a fill from a reader that started before the delete is rejected. Cost: a shorter TTL means more misses and more database load, and leases need support in the cache client. For a profile page I would take the shorter TTL; for something like permissions I would read from the database.

6

Cache write strategies: common questions

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

Write-through confirms a write only after both the cache and the database have it: slower writes, nothing lost. Write-back confirms once the cache has it and writes the database later: faster writes, and anything not flushed is lost if the cache fails.

Is write-behind the same as write-back?

Yes. Both names describe writing to the cache now and to the database asynchronously later. "Write-back" comes from CPU caches; "write-behind" is more common in application caching products.

Cache-aside vs read-through: which should I use?

They behave the same on a miss. In cache-aside the application loads from the database and fills the cache; in read-through the cache layer does it. Cache-aside is the usual choice with Redis or Memcached, because neither loads from your database for you.

What is write-around caching?

Writes go straight to the database and bypass the cache, which is only filled by reads. It suits data that is written often and read rarely or much later, and keeps one-off writes from evicting useful entries.

Which strategy does Redis use?

None by itself. Redis is the store; the strategy lives in your application code or in a caching library around it. Most applications use Redis with cache-aside reads and delete-on-write.

7

Your turn

60-second self-check

Pick a write strategy for each and say why: (a) a video's view count, (b) a user's display name, (c) an account balance.

Stuck? Take one hint at a time0 of 2 used
0 / 25 characters
8

Learn it from the source