What is the write-around cache pattern, and when does it beat write-through?
Write-around skips the cache on writes entirely, trading a guaranteed first-read miss for a simpler, faster write path on data nobody rereads right away.
LEARN BY DOINGPut your intuition to work3 steps
What is the write-around cache pattern, and when does it beat write-through?
Use the lesson’s examples and explanation to check your idea.
Personal reflection. Nothing is sent to an AI service.#Three ways to place a write relative to the cache
Every caching write strategy answers the same question: when data changes, what happens to the cache at the moment of the write? There are three common answers:
- Write-through — the write goes to the cache and the database together (or the cache sits in front and writes through to the DB itself), so the cache is always up to date immediately after a successful write.
- Write-back (write-behind) — the write lands in the cache first and is flushed to the database asynchronously, later.
- Write-around — the write goes straight to the database only. The cache is not touched at all (or is explicitly invalidated, not updated), and the only way an entry ends up in the cache is through the normal read path (cache-aside: read, miss, load from DB, populate cache).
Write-around is often the one people forget exists, because it looks like "doing nothing special" — but that's precisely its value.
#What write-around actually looks like
import jsonfrom typing import Optionalimport redisr = redis.Redis(host="localhost", port=6379, decode_responses=True)CACHE_TTL_SECONDS = 300def write_around_update(product_id: str, fields: dict) -> None:"""Write-around: the write goes straight to the database.We don't set the cache here -- that's the whole point of the pattern.We do invalidate any stale copy so a read right after doesn't return it."""db.update_product(product_id, fields)r.delete(f"product:{product_id}")def read_with_cache_aside(product_id: str) -> Optional[dict]:"""The cache only gets populated lazily, on a read miss."""key = f"product:{product_id}"cached = r.get(key)if cached is not None:return json.loads(cached)product = db.get_product(product_id)if product is None:return Noner.setex(key, CACHE_TTL_SECONDS, json.dumps(product))return product
Notice what's missing compared to write-through: there's no r.set(key, new_value) anywhere in the write path. The write function's only cache-related job is to make sure a stale copy doesn't linger — it deletes, it never sets.
#When write-around wins
Write-around is the right default whenever a piece of data is written far more often than it's read, or where the specific record just written is unlikely to be the next thing read. Classic examples: bulk data imports, audit/event logs, analytics ingestion, a backfill script updating millions of rows overnight, or any write-heavy table that's mostly queried in aggregate rather than by the exact row you just touched. In all of these, write-through would mean paying the cost of a cache write (extra network round-trip, potential serialization cost, cache memory pressure) for data that's statistically unlikely to ever be read from cache before its TTL expires anyway. Write-around avoids polluting the cache with cold data and keeps the write path fast and simple — it's one fewer network hop per write, and it doesn't add a new failure mode (what happens if the cache write fails but the DB write succeeded?) to your write path at all.
#Where it costs you
The tradeoff is the mirror image of its benefit: the first read after a write is always a guaranteed miss. If your application (or the same request) reads back the value it just wrote — a classic "read your own write" pattern, like showing a confirmation page right after a form submission — write-around forces that first read to go to the database, adding latency exactly when a user is watching. Write-through doesn't have this problem, because the cache already holds the fresh value the instant the write completes.
#Side-by-side
| Write-through | Write-around | |
|---|---|---|
| Write latency | Higher (DB + cache, same request) | Lower (DB only) |
| Read right after write | Cache hit, fresh | Guaranteed cache miss |
| Cache pollution from cold data | High (everything written gets cached) | Low (only what's actually read gets cached) |
| Best for | Read-heavy data, read-after-write flows | Write-heavy data rarely re-read immediately |