← Blog
Jan 23, 2026·6 min read

Caching Strategies and the Cache-Invalidation Trap

A practical guide to caching patterns — cache-aside, write-through, write-back — and how to dodge the stale-data traps that make cache invalidation famously hard.

There are only two hard things in computer science, the joke goes, and cache invalidation is the one that actually ships bugs to production. Caching is the cheapest performance win you'll ever buy — until a stale value serves a customer the wrong balance. Let's make the trade-offs concrete.

Why you cache at all

A cache trades freshness for speed and load reduction. You're betting that the same data gets read far more often than it changes — the read-heavy world most services live in. Get the pattern right and you cut p99 latency and database load in one move. Get it wrong and you ship confusing, intermittent staleness that's brutal to debug.

The three patterns worth knowing

Most real systems are built from these. Pick by who owns the write.

  • Cache-aside (lazy loading): the application reads the cache, and on a miss loads from the database and populates it. Writes go straight to the database and invalidate the cached key. Simple, resilient, and the default for a reason. The cost: the first read after a write is always a miss.
  • Write-through: every write goes to the cache and the database together, synchronously. Reads are always warm, but writes pay the extra hop and you cache data nobody may ever read.
  • Write-back (write-behind): writes hit the cache and flush to the database asynchronously. Blazing write throughput, but a cache node crash can lose data. Reserve it for tolerant workloads like counters and metrics.

The invalidation trap

The hard part is never the happy path. It's keeping the cache honest when data changes. Three traps catch teams over and over:

  • Stale on write: you update the database but the cache still holds the old value. The fix is to invalidate, don't update — delete the key and let the next read repopulate from the source of truth. Updating the cached value directly invites a race where a slow read writes a stale value back after your delete.
  • Thundering herd: a hot key expires and a thousand concurrent requests all miss and stampede the database at once. Mitigate with a short lock or single-flight so only one request recomputes, plus jittered TTLs so keys don't all expire together.
  • TTL as a crutch: a TTL bounds staleness but never eliminates it. If correctness matters, invalidate explicitly on write and treat the TTL as a backstop, not the primary mechanism.

Eviction is a policy choice

When the cache fills, something has to go. LRU (least recently used) is the sane default for most access patterns. LFU (least frequently used) wins when popularity is stable over time. Whatever you pick, size the cache to your working set — a cache that can't hold the hot data thrashes and quietly stops helping.

A short decision rule

  • Read-heavy, tolerant of brief staleness: cache-aside with TTL.
  • Reads must always be fresh and writes are modest: write-through.
  • Write-heavy and loss-tolerant: write-back.

Caching shows up everywhere downstream — a URL shortener leans on it for hot redirects, and so does almost every read API you'll build. To get the underlying instincts automatic, the System Design lessons cover cache placement and consistency, and the broader Learn track ties it into data modeling.

Put it under pressure

Knowing the patterns and defending a cache design against a sharp interviewer are different skills. Jump into the arena, pick a design problem at your tier from the roadmaps, and find out whether your invalidation story holds up when the machine starts poking holes.

Stop reading. Start climbing.

Every problem pits you against an AI of your tier.

Enter the arena →