Your menu page is viewed a thousand times a day, but the menu changes once a week. Yet every single view fires the same query at the database and brings the same data. It is a bit like this - looking up the same address by opening the notebook again and again, when saving the address in your phone would have done it. A cache is that saved arrangement: keeping frequently needed data in a fast place (Redis - it lives in memory), so you do not have to go to the database every time.
The cache-aside pattern - the most used shape
async function getMenu() {
const cached = await redis.get("menu:all");
if (cached) return JSON.parse(cached); // cache hit
const menu = await db.menu.findMany(); // cache miss - from the database
await redis.set("menu:all", JSON.stringify(menu), "EX", 300); // 5 minute TTL
return menu;
}The shape is simple: first look in the cache, and if you find it, return it at once. If not, bring it from the database and keep it in the cache, so the next person gets it. EX 300 is the TTL - after 5 minutes the cache deletes itself, and the next request brings fresh data.
Invalidation - the cache's real hard problem
The cache's most complex question is: when the data changes, when do you remove the old cache? The admin changed a price on the menu, but the old price stayed in the cache - the customer will see the wrong price. There are two weapons: TTL (expiring on its own - for places where seeing slightly old data sometimes is acceptable), and active invalidation - deleting the related cache key the moment the data changes.
// The moment a price changes, drop the menu cache
async function updateMenuItem(id, data) {
const item = await db.menu.update({ where: { id }, data });
await redis.del("menu:all");
return item;
}What to cache is also a matter of judgement: things that are read often but change rarely (menu, settings, popular products) - those. Things that are different every time or must always be exactly right (bank balance, the final state of stock) - be careful there, or do not cache at all.
The mistake everyone makes
Caching without arranging TTL or invalidation - then old data keeps circulating forever. The opposite is also a mistake: caching everything. The more the cache grows, the more the stale-data risk grows. Cache only where the benefit is clear.
Today's practice
Put Redis in your API and add the cache-aside pattern to a menu or product list endpoint. Then send two requests and measure the time - the first time from the database, the second time from the cache. Finally, update an item and check whether invalidation is working.
How to say it in an interview
I use the cache-aside pattern - I look in Redis first, and if I do not find it I bring it from the database and keep it with a TTL. For invalidation, where changed data must show at once, I delete the key at update time; where slightly old data is fine, TTL alone is enough.