Build the mental model
With cache-aside, the application reads Redis first, falls back to PostgreSQL on a miss, and stores the result with a TTL. On writes, commit the database change before deleting related cache keys. High hit rates help latency, but stale data, stampedes, and cold starts must be designed explicitly.
Connect it to a real scenario
Cache tutorial details under `tutorial:42:v1`. On a miss, use parameterized SQL, serialize the result, and set it with a jittered TTL. Delete the key after a successful update commit. If Redis is unavailable, fall back to the database with overload protection.
Try the working example
async function getTutorial(id: number) {
const key = `tutorial:${id}:v1`;
const cached = await redis.get(key);
if (cached) return JSON.parse(cached);
const tutorial = await db.oneOrNone(
'SELECT id, title, summary FROM tutorials WHERE id = $1', [id]
);
if (tutorial) await redis.set(key, JSON.stringify(tutorial), { EX: 300 + Math.floor(Math.random() * 30) });
return tutorial;
}The first request reads PostgreSQL; later requests hit Redis until expiry or invalidation.5-minute try-it
Design the key scheme, TTL, and invalidation events for paginated tutorial lists.
One important caution
Deleting cache before the database update can let a concurrent reader repopulate the old value.
Redis — Client-Side Caching — Redis