An interviewer asked: "What caching strategy does your app use?"
The candidate said: "We use Redis."
Interviewer: "That's a tool. I asked for a strategy."
Silence. Interview over. ๐ถ
Here's every caching strategy broken down ๐
๐ง ๐ช๐ต๐ฎ๐ ๐ถ๐ ๐๐ฎ๐ฐ๐ต๐ถ๐ป๐ด?
๐ Storing data temporarily so future requests are served faster
๐ Avoids hitting the original source โ DB, API, server โ every time
๐ Wrong strategy = stale data, crashes, data loss
Without cache: User โ Server โ Database (slow ๐ข)
With cache: User โ Cache (fast โก)
โ miss only
Database
โ Reduces latency
โ Reduces database load
โ Scales better under traffic
โก 1๏ธโฃ ๐๐ฎ๐ฐ๐ต๐ฒ-๐๐๐ถ๐ฑ๐ฒ (๐๐ฎ๐๐ ๐๐ผ๐ฎ๐ฑ๐ถ๐ป๐ด)
๐ App checks cache first. Miss โ fetch DB โ store in cache.
async function getUser(id) {
// Step 1 โ check cache
const cached = await redis.get(`user:${id}`);
if (cached) return JSON.parse(cached);
// Step 2 โ cache miss, hit DB
const user = await db.findUser(id);
// Step 3 โ store in cache for next time
await redis.set(`user:${id}`, JSON.stringify(user), 'EX', 3600);
return user;
}
โ Only caches what's actually requested
โ Cache failure doesn't break the app
โ First request always slow โ cold cache
โ Risk of stale data between TTL cycles
๐ฏ 2๏ธโฃ ๐ช๐ฟ๐ถ๐๐ฒ-๐ง๐ต๐ฟ๐ผ๐๐ด๐ต
๐ Every write goes to cache AND database simultaneously
async function updateUser(id, data) {
// Write to DB and cache together
await db.updateUser(id, data);
await redis.set(`user:${id}`, JSON.stringify(data), 'EX', 3600);
}
โ Cache always in sync with DB
โ No stale reads after writes
โ Write latency increases โ two writes every time
โ Cache fills with data that may never be read
๐ Best for: Read-heavy apps where freshness is critical
๐ 3๏ธโฃ ๐ช๐ฟ๐ถ๐๐ฒ-๐๐ฒ๐ต๐ถ๐ป๐ฑ (๐ช๐ฟ๐ถ๐๐ฒ-๐๐ฎ๐ฐ๐ธ)
๐ Write to cache instantly. Sync to DB asynchronously later.
User writes โ Cache โ
(instant response)
โ async worker (batched every 5s)
Database ๐ (eventually consistent)
async function updateScore(userId, score) {
// Instant write to cache
await redis.set(`score:${userId}`, score);
// Add to queue โ worker syncs to DB later
await queue.add('syncScore', { userId, score });
}
โ Blazing fast write performance
โ Reduces DB write load โ batch updates
โ Risk of data loss if cache crashes before sync
โ Complex to implement correctly
๐ Best for: Leaderboards, analytics, gaming, counters
๐ 4๏ธโฃ ๐ฅ๐ฒ๐ฎ๐ฑ-๐ง๐ต๐ฟ๐ผ๐๐ด๐ต
๐ App only talks to cache. Cache fetches from DB on miss.
App โ Cache โ (hit) โ App โ
App โ Cache โ (miss) โ DB โ Cache populates โ App โ
// App never touches DB directly
const user = await cacheProvider.get(`user:${id}`);
// Cache provider handles DB fetch internally on miss
โ App logic stays clean โ zero cache handling code
โ Cache always populated after first request
โ Cache provider must support read-through natively
โ First request latency still exists
๐ Best for: Managed caches โ AWS ElastiCache, DAX
โฐ 5๏ธโฃ ๐ฅ๐ฒ๐ณ๐ฟ๐ฒ๐๐ต-๐๐ต๐ฒ๐ฎ๐ฑ
๐ Cache proactively refreshes data before TTL expires
TTL = 60s
At 45s โ background job pre-fetches fresh data
At 60s โ cache already has new data โ
zero miss latency
async function getWithRefreshAhead(key, fetchFn, ttl = 60) {
const cached = await redis.get(key);
const ttlRemaining = await redis.ttl(key);
// Refresh when 75% of TTL has passed
if (ttlRemaining < ttl * 0.25) {
fetchFn().then(data =>
redis.set(key, JSON.stringify(data), 'EX', ttl)
);
}
return cached ? JSON.parse(cached) : fetchFn();
}
โ No latency spikes on cache expiry
โ Always serving warm data
โ May refresh data that's never requested โ wasted compute
๐ Best for: Homepages, dashboards, trending feeds
๐ 6๏ธโฃ ๐๐ฎ๐ฐ๐ต๐ฒ ๐๐ป๐๐ฎ๐น๐ถ๐ฑ๐ฎ๐๐ถ๐ผ๐ป ๐ฆ๐๐ฟ๐ฎ๐๐ฒ๐ด๐ถ๐ฒ๐
๐ Knowing WHEN to clear cache is as important as caching itself
// TTL โ expire after fixed time
await redis.set('user:1', data, 'EX', 3600); // expires in 1hr
// Event-based โ clear on data change
async function updateUser(id, data) {
await db.updateUser(id, data);
await redis.del(`user:${id}`); // invalidate immediately
}
// Cache versioning โ bump version on deploy
const key = `user:${id}:v2`; // old v1 cache naturally expires
โ TTL โ simple, automatic
โ Event-based โ precise, immediate
โ Versioning โ safe for deployments
๐จ ๐๐ฎ๐ฐ๐ต๐ฒ ๐ฃ๐ฟ๐ผ๐ฏ๐น๐ฒ๐บ๐ ๐ฌ๐ผ๐ ๐ ๐๐๐ ๐๐ป๐ผ๐
// Cache Stampede โ TTL expires, 1000 users hit DB together
// Fix: mutex lock โ only one request rebuilds cache
const lock = await redis.set('lock:user:1', 1, 'NX', 'EX', 5);
if (lock) { /* fetch DB and repopulate */ }
else { /* wait and retry */ }
// Cache Penetration โ requests for non-existent data bypass cache
// Fix: cache null values too
await redis.set(`user:${id}`, 'NULL', 'EX', 60);
// Cache Avalanche โ all keys expire at same time
// Fix: add random jitter to TTL
const ttl = 3600 + Math.floor(Math.random() * 300);
โ๏ธ ๐๐ฟ๐ผ๐ป๐๐ฒ๐ป๐ฑ ๐๐ฎ๐ฐ๐ต๐ถ๐ป๐ด (๐ฅ๐ฒ๐ฎ๐ฐ๐)
// React Query โ cache-aside in the frontend
const { data } = useQuery({
queryKey: ['user', id],
queryFn: () => fetch(`/api/user/${id}`),
staleTime: 5 * 60 * 1000, // fresh for 5 mins
cacheTime: 10 * 60 * 1000, // keep in memory for 10 mins
});
โ staleTime โ how long data is considered fresh
โ cacheTime โ how long unused data stays in memory
โ React Query implements cache-aside pattern automatically
๐จ ๐๐ผ๐บ๐บ๐ผ๐ป ๐ ๐ถ๐๐๐ฎ๐ธ๐ฒ๐
โ Caching without a TTL โ stale data lives forever
โ Not handling cache miss gracefully โ app crashes
โ Caching user-specific data globally โ data leaks
โ Using Write-Behind without a reliable queue
โ Ignoring cache stampede on high-traffic TTL expiry
๐ก ๐ฆ๐ฒ๐ป๐ถ๐ผ๐ฟ-๐๐ฒ๐๐ฒ๐น ๐๐ป๐๐ถ๐ด๐ต๐
There are only two hard problems in computer science: cache invalidation and naming things.
Choosing the wrong strategy doesn't slow your app โ it silently corrupts it.
๐ฏ ๐๐ป๐๐ฒ๐ฟ๐๐ถ๐ฒ๐ ๐ข๐ป๐ฒ-๐๐ถ๐ป๐ฒ๐ฟ
Caching strategy is a tradeoff between consistency, latency, and complexity โ Cache-Aside for flexibility, Write-Through for consistency, Write-Behind for write performance, Read-Through for clean app logic, and Refresh-Ahead for zero miss latency โ with the right choice always depending on your read/write ratio, consistency requirements, and failure tolerance.
#SystemDesign #Backend #Caching #Redis #WebDevelopment #InterviewPrep #SoftwareEngineering #PerformanceOptimization #EngineeringMindset


























