Learn / Infrastructure / Lesson 12

Redis, and when you need it

Redis is a fast shared memory for many servers. What it is good at, the incidents that came from using it carelessly, and why a single server usually does not need it at all.

Last updated: 2026-09-20

What it is

Redis is a database that keeps its data in RAM. Reads and writes take well under a millisecond. It stores simple shapes: strings, counters, lists, sets, sorted sets, hashes, and streams. Keys can expire on their own after a set time.

Its real value is not speed. A Map inside your own process is faster still. Its value is that many server processes can share the same memory.

Why it is a rule

Why people reach for it

A single Node process can keep its rate limits, sessions, caches and "who is online" in plain memory. The moment you run two copies behind a load balancer, each copy has its own memory:

Redis gives them one shared memory, so they act as one server again.

What went wrong when it was used carelessly

When Redis is the right tool

Use it when more than one process needs the same fast, short-lived state:

NeedWhy Redis fits
Rate limiting across several serversINCR with an expiry is one atomic counter everyone shares
Sessions across several serversAny server can read any session
Live messages across servers (socket.io, chat, presence)Pub/sub, or the socket.io Redis adapter, delivers a message to users on every server
Background job queues (BullMQ and similar)Reliable lists with retries, delays and priorities
A shared cache of expensive resultsEvery server benefits when one computes it; keys expire by themselves
Leaderboards and countersSorted sets and atomic increments are built in
Locks between serversA short-lived key stops two servers doing the same job at once

When it is not

How to do it safely

Never expose it

text
bind 127.0.0.1 ::1        # listen on the private network only
protected-mode yes
requirepass <long random secret>

Use a managed Redis on a private network, require a password or ACL user, and use TLS when it travels between machines.

Key everything by who can see it

A cached value is keyed by everything its access check depends on: the tenant, the user, the role.

js
const key = `ledger:${companyId}:${period}`
await redis.set(key, JSON.stringify(summary), { EX: 300 })

A key of ledger:${period} alone would hand one company's summary to the next company that asks.

Always set an expiry

A key with no expiry lives until memory runs out. Give cached values a TTL, and set a maxmemory limit with an eviction policy, so a full Redis drops old cache rather than refusing writes.

Plan for it to be down

The app should keep working, slower, when Redis is unavailable: read from the database instead of the cache. A cache that takes the whole site down when it fails has made the site less reliable, not more.

How we do it here

We do not use Redis. The app runs as a single instance, so rate limits, page caches, live presence and socket messages all live in plain memory inside one process. That is the fastest option and one less thing to run. The day the app needs a second instance, Redis (or Valkey) comes in for exactly three things: the socket.io adapter, live presence, and shared rate limits.

Benefits

Disadvantages

Checklist

Sources

Read this lesson as Markdown