Skip to main content

Caching

The fastest query is the one you never send. A cache keeps hot data in fast storage (usually in-memory, often Redis) so repeated reads skip the database entirely - cutting latency and shielding the database from load. The cost is a second copy of the data that can go stale, so caching is mostly about when to trust it and when to throw it away.

Cache-aside (the default)

By far the most common pattern. The application checks the cache first; on a miss it reads the database and populates the cache for next time:

async function getProduct(id) {
const key = `product:${id}`;
const hit = await cache.get(key);
if (hit) return JSON.parse(hit); // cache hit

const row = await db.query('SELECT * FROM products WHERE id = $1', [id]);
await cache.set(key, JSON.stringify(row), {EX: 300}); // cache for 5 min
return row;
}

The cache only holds what has actually been requested, and the app controls exactly what is cached.

Write strategies

When the underlying data changes, the cached copy must be dealt with:

  • Write-through - write to the cache and the database together, so the cache is always current (slower writes).
  • Write-behind - write to the cache now, flush to the database asynchronously (fast, but risks loss).
  • Cache-aside + invalidate - the common pairing: on a write, update the database and delete the cached key so the next read re-fetches.

TTL and invalidation

Two levers keep a cache from serving stale data:

  • TTL (time to live) - entries expire after a set time (the EX: 300 above). Simple, and bounds how stale data can get.
  • Explicit invalidation - on a write, delete or update the affected keys immediately.

"There are only two hard things in computer science: cache invalidation and naming things." Knowing which keys a write affects is the genuinely hard part.

What to cache, and the pitfalls

Cache hot reads and expensive queries - dashboards, computed aggregates, sessions, things read far more than written. Do not cache everything; rarely-read data just wastes memory and adds a staleness risk.

Watch for:

  • Stale reads - the cached copy lags the database (often acceptable; sometimes not).
  • Thundering herd / stampede - a popular key expires and thousands of requests hit the database at once. Mitigate with slightly randomized TTLs or a single-flight lock that lets one request refill while others wait.

Quick quiz

Caching

3 questions

1In the cache-aside pattern, what happens on a cache miss?

2What is the most common way to keep a cache fresh after a write (cache-aside)?

3What is a cache stampede (thundering herd)?

Next up

With the application patterns in place, the last lesson steps back to running the database itself: Operating a database - backups you can actually restore, slow-query analysis, and the metrics worth watching in production.