Skip to content

Upgrading from v5 to v6

Pavel Pashov edited this page Jul 10, 2026 · 2 revisions

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 connect to ready when 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.

Clone this wiki locally