-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Upgrading from v5 to v6
ioredis v6 adopts RESP3 by default while keeping RESP2-compatible reply shapes. This guide provides a checklist of changes to review when upgrading from v5.
-
Make sure your project uses Node.js 20 or newer.
-
Review the RESP3 connection handshake.
v6 sends HELLO 3 when a connection opens, including AUTH when credentials
are configured. If Redis returns NOPROTO or an unknown-command error, ioredis
retries with RESP2. Other errors fail the connection.
To keep the v5 wire protocol, or support a proxy that rejects HELLO
differently:
const redis = new Redis({ protocol: 2 });- Choose a reply mapping.
replyMapping controls how RESP3-only types are returned:
"legacy" (default) keeps v5/RESP2 shapes. "resp3" returns RESP3 shapes and
requires protocol: 3.
const redis = new Redis({ protocol: 3, replyMapping: "resp3" });
await redis.config("GET", "maxmemory"); // { maxmemory: "0" } instead of ["maxmemory", "0"]
await redis.zscore("zset", "member"); // 1.5 instead of "1.5"| RESP3 type |
"legacy" (default) |
"resp3" |
|---|---|---|
Map (%) |
flat [key, value, ...] array |
plain object with string keys |
Double (,) |
string | number |
Boolean (#) |
0 / 1
|
boolean |
Sets remain arrays. Big numbers and verbatim strings remain strings.
Command-specific transformers still apply, so hgetall() returns an object
with either mapping. stringNumbers: true returns integers and doubles as
strings.
If a "resp3" connection falls back to RESP2, replies use legacy shapes and a
warning is logged.
Under "resp3", map keys are UTF-8 strings even for Buffer variants such as
hgetallBuffer(). Their values remain buffers. Use "legacy" for binary map keys;
use a custom reply transformer if hgetallBuffer() must return Buffer keys.
- Review Pub/Sub behavior.
RESP3 connections allow regular commands while subscribed, and redis.mode
remains "normal". Pub/Sub events and subscribe/unsubscribe replies are
unchanged. RESP2 connections retain the v5 subscriber-mode restrictions.
- Move commands from
connecttoreadywhen the offline queue is disabled.
With enableOfflineQueue: false, commands sent from a connect listener may
now reject before the client is ready:
Stream isn't writeable and enableOfflineQueue options is false
This includes subscribe(), which v5 could send during connect. Send these
commands from ready, or keep the offline queue enabled:
const redis = new Redis({ enableOfflineQueue: false });
redis.once("ready", () => {
void redis.subscribe("updates");
});- Set RESP options in the correct place for Cluster and Sentinel.
Cluster node options belong under redisOptions:
const cluster = new Redis.Cluster(nodes, {
redisOptions: { protocol: 3, replyMapping: "resp3" },
});Sentinel uses top-level Redis options:
const redis = new Redis({
sentinels: [{ host: "localhost", port: 26379 }],
name: "mymaster",
protocol: 3,
replyMapping: "resp3",
});Each Cluster node or Sentinel endpoint negotiates independently.
- For TypeScript projects, review RESP3 return types.
Passing replyMapping: "resp3" as a literal selects RESP3 return types:
const redis = new Redis({ protocol: 3, replyMapping: "resp3" });
await redis.zscore("zset", "member"); // number | null (string | null on default clients)duplicate() preserves the mapping unless overridden. Cluster clients infer it
from redisOptions.replyMapping.