---
title: Redis, and when you need it
summary: 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.
topic: infrastructure
order: 5
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:

- A visitor's rate limit is split in two, so they get twice the allowance.
- A user connected to server A never hears a live message sent from server B.
- A cache on server A is cold on server B.

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

### What went wrong when it was used carelessly

- **Open Redis on the internet (2015 onwards).** Redis once shipped with no password and
  listened on every network interface by default. Attackers scanned for open instances, used
  Redis's own config commands to write their SSH key onto the server, and took the whole
  machine. Tens of thousands of servers were found open. Redis later added "protected mode",
  which refuses outside connections unless you set a password.
- **ChatGPT (March 2023).** A bug in the Redis client library that OpenAI used meant a request
  cancelled at the wrong moment could leave its answer in a shared connection. The next user
  received it. For a few hours, some users saw other people's chat titles, and some payment
  details were shown to the wrong subscribers. A shared cache is a place where one person's data
  can reach another.
- **The licence change (2024).** Redis moved away from its open-source BSD licence to
  source-available licences, and the Linux Foundation started **Valkey**, a fork of the last
  open version, backed by the big cloud providers. Redis later added the AGPL as an option.
  Check the licence of the version and the host you pick.

## When Redis is the right tool

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

| Need | Why Redis fits |
| --- | --- |
| Rate limiting across several servers | `INCR` with an expiry is one atomic counter everyone shares |
| Sessions across several servers | Any 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 results | Every server benefits when one computes it; keys expire by themselves |
| Leaderboards and counters | Sorted sets and atomic increments are built in |
| Locks between servers | A short-lived key stops two servers doing the same job at once |

## When it is not

- **You run one server.** A `Map` in memory is faster, has no network hop, and cannot go down on
  its own. Add Redis the day you add a second instance, not before.
- **As your main database.** By default Redis can lose the last second or more of writes in a
  crash, and when memory runs out it may evict keys. Money, bookings and anything you must keep
  belongs in Postgres or another durable database.
- **To hide a slow query.** If a query is slow because it is missing an index, add the index.
  A cache in front of a bad query adds a second system and stale data, and the query is still
  bad.
- **For data that must never be stale.** Every cache is a trade: speed for the chance of an
  old answer. Balances and stock levels that decide a sale should come from the database.

## 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

- Lets several servers share state as if they were one.
- Sub-millisecond reads and atomic operations for counters, locks and queues.
- Expiring keys make caches and limits clean themselves up.

## Disadvantages

- One more service to run, secure, monitor, back up and pay for.
- Data in RAM is expensive, and by default not fully durable.
- A network hop on every access: slower than a local `Map` for a single server.
- A shared cache can leak data between users if a key or a client library is wrong.

## Checklist

- More than one instance needs this state; otherwise, keep it in memory.
- Redis is on a private network with a password, never public.
- Every key includes the tenant or user it belongs to.
- Every cached key has an expiry, and `maxmemory` is set.
- The app still works, slower, when Redis is down.

## Sources

- [Redis — Security](https://redis.io/docs/latest/operate/oss_and_stack/management/security/)
- [Redis — Key eviction](https://redis.io/docs/latest/develop/reference/eviction/)
- [socket.io — Redis adapter](https://socket.io/docs/v4/redis-adapter/)
- OpenAI, *March 20 ChatGPT outage: here's what happened*, March 2023.
- [Valkey](https://valkey.io/)
