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.