Caching with Redis (ioredis)
Caching stores the result of slow work — like a database query — in fast in-memory storage such as Redis, so repeated requests are served instantly instead of redoing the work every time.
Learn Caching with Redis (ioredis) in our free Node.js course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Node.js course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll learn why caching matters, how Redis GET / SET with a TTL work, the cache-aside pattern, how to use the ioredis client, and how to invalidate stale entries on writes.
What You'll Learn in This Lesson
1️⃣ GET, SET & TTL
A cache is a key/value store. You SET a key to a value and later GET it. The crucial extra is a TTL (time to live): with Redis you write SET key value EX 60 to make the entry vanish after 60 seconds. The model below behaves the same way — a fresh key is a hit , a missing or expired key is a miss .
2️⃣ The Cache-Aside Pattern
The everyday strategy is cache-aside : check the cache first; on a miss , do the slow work, store the result, and return it; on a hit , return the cached value immediately. The first request "warms" the cache and pays full price; every request after is fast. The runnable example simulates a 50 ms database call so you can measure the difference for real.
3️⃣ The Real Thing: ioredis & Invalidation
With ioredis , the same pattern uses real commands: await redis.get(key) , then on a miss await redis.set(key, value, 'EX', 60) . Because Redis stores strings, you JSON.stringify on the way in and JSON.parse on the way out. Crucially, when data changes , delete its key with redis.del(key) so the next read repopulates fresh — this is invalidation .
Your turn. The memoizer below works once you fill in the single blank marked ___ . Follow the 👉 hint, then run it.
No blanks — just a brief and an outline. Implement read-through caching plus invalidation: a write must delete the cached key so the next read sees fresh data. Build it, run it, and compare with the example output.
📋 Quick Reference — Redis Caching (ioredis)
Practice quiz
What is the main purpose of caching?
- To encrypt data
- To serve repeated reads from fast memory instead of redoing slow work
- To back up the database
- To compress files
Answer: To serve repeated reads from fast memory instead of redoing slow work. A cache stores results of expensive work so later identical requests are served instantly.
In the cache-aside pattern, what happens on a cache miss?
- The request fails
- Nothing is returned
- Fetch from the source, store in cache, then return it
- The cache is cleared
Answer: Fetch from the source, store in cache, then return it. On a miss you load from the real source, store the result with a TTL, and return it.
What does TTL (the Redis EX option) control?
- How long a cached entry stays valid before auto-deletion
- The maximum value size
- The number of clients
- The connection port
Answer: How long a cached entry stays valid before auto-deletion. TTL is the time to live; after it elapses Redis automatically removes the key.
With ioredis, how do you set a key with a 60-second expiry?
- redis.set(key, v)
- redis.expire(key)
- redis.setex(60)
- redis.set(key, v, 'EX', 60)
Answer: redis.set(key, v, 'EX', 60). Passing 'EX', 60 to set stores the value and gives it a 60-second TTL.
Because Redis stores strings, what must you do with objects?
- JSON.stringify before SET and JSON.parse after GET
- Nothing, Redis stores objects
- Use redis.object()
- Convert them to buffers manually
Answer: JSON.stringify before SET and JSON.parse after GET. Redis values are strings, so serialize with JSON.stringify and deserialize with JSON.parse.
Which ioredis command invalidates a cached key on a write?
- redis.get
- redis.del
- redis.set
- redis.ttl
Answer: redis.del. redis.del removes the key so the next read repopulates fresh data.
Why is Redis preferred over an in-process Map for caching across servers?
- It is written in JavaScript
- It is slower but safer
- It is shared across all processes and servers
- It never expires data
Answer: It is shared across all processes and servers. An in-process Map is per-instance, while Redis is a shared store all instances can use.
What is the cost of the very first read of each key in cache-aside?
- It is always a hit
- It is a miss (a cold cache)
- It throws an error
- It returns null forever
Answer: It is a miss (a cold cache). The first read for a key misses and pays full cost; subsequent reads are hits.
What error usually means no Redis server is running?
- EACCES
- ENOENT
- ETIMEDOUT
- ECONNREFUSED 127.0.0.1:6379
Answer: ECONNREFUSED 127.0.0.1:6379. ECONNREFUSED on the Redis port means nothing is listening; start a Redis server first.
Why should you always set a TTL on cache entries?
- It encrypts the entry
- It bounds memory and limits how long stale data can survive
- It makes reads slower
- It is required to connect
Answer: It bounds memory and limits how long stale data can survive. A TTL caps memory use and acts as a backstop if invalidation is ever missed.