Cache
A cache is a fast, temporary storage layer that stores results of expensive operations (database queries, API calls, computations) so subsequent requests for the same data can be served faster without repeating the expensive work.
Explanation
Caching is the fundamental performance optimization: avoid repeating expensive work by storing the result and reusing it. This principle appears at every level: CPU caches, OS page cache, browser caches, and application-level caches (Redis, Memcached). Cache patterns: Cache-Aside (lazy loading) — on a cache miss, fetch from the database, store in cache, return; on subsequent requests, return from cache. This is the most common pattern. Write-Through — write to cache and database simultaneously (no stale data, but slower writes). Write-Behind — write to cache, asynchronously persist to database (fast writes, but data may be lost if cache fails before persisting). Eviction policies determine what to remove when cache is full: LRU (Least Recently Used) — removes the item accessed least recently; good general-purpose. LFU (Least Frequently Used) — removes the item accessed least often; better for skewed access patterns. TTL (Time-To-Live) — removes items after a fixed duration; simple, predictable staleness. "There are only two hard things in Computer Science: cache invalidation and naming things." When underlying data changes, cached copies must be updated or removed. Strategies: TTL expiry (accept staleness up to N seconds), event-driven invalidation (on write, delete the cache entry), versioned keys (embed version in key, increment on update).
Code Example
javascript// Redis cache-aside pattern (Node.js)
const redis = require('redis');
const client = redis.createClient({ url: process.env.REDIS_URL });
await client.connect();
async function withCache(key, ttlSeconds, fetchFn) {
const cached = await client.get(key);
if (cached) return JSON.parse(cached); // cache hit
const data = await fetchFn(); // cache miss: fetch from source
await client.setEx(key, ttlSeconds, JSON.stringify(data));
return data;
}
// Cache expensive DB query for 5 minutes
app.get('/api/products', async (req, res) => {
const products = await withCache(
'products:all',
300,
() => db.query('SELECT * FROM products WHERE active = true')
);
res.json(products);
});
// Invalidate on write
app.put('/api/products/:id', async (req, res) => {
await db.query('UPDATE products SET ...', [req.body, req.params.id]);
await client.del('products:all'); // invalidate cached list
res.json({ ok: true });
});
Why It Matters for Engineers
Caching is one of the highest-impact performance improvements in backend development. A query that takes 100ms from PostgreSQL takes 1ms from Redis — a 100x speedup. For high-traffic endpoints, this translates to dramatically reduced database load, lower infrastructure costs, and better user experience. Caching is also essential systems design knowledge. 'Design a URL shortener,' 'design Twitter,' and 'design a leaderboard' all involve caching decisions. Knowing cache strategies, eviction policies, and invalidation patterns is expected at senior engineer interviews.
Related Terms
Memoization · CDN · Database Sharding · Eventual Consistency
Learn This In Practice
Go deeper with the full module on Beyond Vibe Code.
Systems Design Fundamentals → →