Caching with Redis: Fast Reads Without Hammering Your Database
What Is a Cache?
A cache is a fast, temporary store that sits between your application and your database. When you need data, you check the cache first. If it's there, you skip the database entirely. If it's not, you fetch from the database, then store the result in the cache for next time.
Redis is the most common cache in production. It keeps everything in RAM. A Redis read takes ~0.1ms. A database read takes 5–50ms. At scale, that difference compounds.
The Problem It Solves
Databases are expensive to read under load. If 50,000 users all want to see the same trending post, your database doesn't need to process that query 50,000 times. It needs to process it once. Redis answers the other 49,999 requests from memory.
Caching solves two things:
- Latency — in-memory reads are 10–500x faster than disk-based databases
- Database load — redirect the majority of reads away from your primary DB
Rule of thumb
How It Works
The standard pattern is cache-aside (also called lazy loading):
- Request comes in — check Redis first
- Cache hit: data is in Redis → return it immediately
- Cache miss: data not in Redis → query the database → store result in Redis with a TTL → return the data
| 1 | Request → Redis? |
| 2 | Yes → return (fast) |
| 3 | No → DB query → store in Redis → return (slow, once) |
TTL (Time-To-Live) controls how long data lives in the cache. After the TTL expires, the next request is a cache miss and refreshes the data.
When to Add It
Add Redis caching when:
- Your system is read-heavy — more reads than writes
- The same data is requested repeatedly by many users
- You have a latency target below what your DB can consistently deliver (<10ms)
- Your DB is becoming a bottleneck under read load
When to use
When NOT to Add It
- Write-heavy systems — data changes too fast, cache is stale before anyone reads it
- Strong consistency required — cached data is always potentially stale by definition
- Simple systems with light load — you're adding infrastructure you don't need yet
Warning
Cache Invalidation — the Hard Part
Cache invalidation is famously one of the hardest problems in CS. There are only three strategies:
- TTL-based expiry — set a TTL, accept stale data during that window. Simple but imprecise.
- Write-through — update both the DB and the cache on every write. Always fresh, but every write is slightly slower.
- Explicit invalidation — delete or update the cache key whenever the underlying data changes. Precise but requires discipline — miss one write path and you serve stale data indefinitely.
Common mistake
Redis Beyond Caching
Redis is also commonly used for:
- Session storage — fast, with automatic expiry
- Rate limiting — atomic increment counters with TTL
- Pub/sub — lightweight message passing between services
- Distributed locks — SETNX-based locking
It started as a cache. It's become general-purpose fast state.
Real World
Twitter caches timelines in Redis. A single read for your home feed touches dozens of user timelines — hitting PostgreSQL for every one would be too slow. Redis makes that sub-20ms.
Instagram used Redis extensively for their home feed. At their scale, a 1ms improvement in cache hit latency saves thousands of server-hours per month.
Takeaways
- Redis is an in-memory key-value store — reads are ~0.1ms vs 5–50ms for a database
- Use it for read-heavy systems where the same data is requested repeatedly
- Cache-aside (lazy loading) is the standard pattern
- TTL controls freshness — shorter TTL = fresher data but more DB load
- Cache invalidation is where most bugs hide — design it explicitly, don't wing it
- Don't cache write-heavy or consistency-critical data