In short
The fastest database query is the one you never run. Caching keeps a copy of answers you've already worked out, so the next person gets them in a blink.
Storing the result of an expensive operation so future requests can reuse it instead of recomputing — one of the most effective and most misused performance techniques in backend systems.

Think of it like this
The kirana shop counter
A kirana uncle keeps biscuits, Maggi and matchboxes on the shelf right beside him, and the rice sacks in the godown at the back. Popular things are within arm's reach; everything else is a walk away. A cache is that front shelf: small, fast, and stocked with what's asked for most.
Watch it happen
GET /products/42, thousands of times an hour
No cache
- Every request runs the same SQL query
- Database load grows with every visitor
- Pages slow down when traffic spikes
With cache
- The first request fills the cache
- Repeat requests read from memory
- Database sees a small share of traffic
Cache data that's read often and changes rarely. Decide up front how stale a cached copy is allowed to get.
The big ideas
What you need to know
Hit or miss
A hit means the answer was already in the cache. A miss means you fetch it from the source and usually store it.
Every copy can go stale
Cached data is a snapshot. A TTL (time to live) says how long that snapshot may be trusted.
Caches stack up
Browser, CDN, app memory, Redis, then the database. Each layer catches requests before the next one.
Space is limited
When a cache fills up, an eviction policy like LRU (least recently used) throws out old entries.
See it in code
Walk through the code
1const cache = new Map<string, { value: unknown; expires: number }>();2let hits = 0, misses = 0;3 4export async function cached<T>(key: string, ttlMs: number, load: () => Promise<T>): Promise<T> {5 const entry = cache.get(key);6 if (entry && entry.expires > Date.now()) {7 hits++;8 return entry.value as T;9 }10 misses++;11 const value = await load();12 cache.set(key, { value, expires: Date.now() + ttlMs });13 return value;14}15 16// const product = await cached("product:42", 60_000, () => db.products.find(42));1/3Look for a fresh entry. If it hasn't expired, that's a hit and the database is skipped.
hits / (hits + misses) is your hit ratio. If it stays low, you're caching the wrong things or the TTL is too short.
Save yourself the pain
Common mistakes
Oops
Caching everything, including data that changes every second.
Do this instead
Cache what's read often and changes rarely. Fast-changing data gives low hit rates and stale answers.
Oops
Adding a cache without deciding how it gets refreshed.
Do this instead
Before writing code, decide the TTL and what happens when the source data changes.
Your mission
Measure a cache
Quick check
A product page is cached for 5 minutes. The price changes at minute 1. What do users see until minute 5?
Go deeper
- 1Identify one expensive operation in a project that's a good caching candidate.
- 2Measure response time with and without caching for the same endpoint.
- 3Learn the golden rule: cache invalidation is the hard part, not the caching itself.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.