Caching is the fastest way to make a read-heavy app feel instant, and the fastest way to serve stale data if you get invalidation wrong.
Cache-aside is the default
The app checks the cache, falls back to the database on a miss, and writes the result back:
let user = await redis.get(key);
if (!user) {
user = await db.users.find(id);
await redis.set(key, user, 'EX', 3600);
}Choose an invalidation approach
- TTLs for data that can be briefly stale.
- Explicit deletes on write for data that must be fresh.
- Versioned keys when a single change invalidates many entries at once.
Watch the edges
Guard against cache stampedes on hot keys, and never let the cache become the source of truth. It is an optimization, not your database.