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.