Migrate from ioredis
Discover the differences between ioredis
and node-redis
.
Redis previously recommended the ioredis
client library for development with Node.js,
but this library is now deprecated in favor of
node-redis
. This guide
outlines the main similarities and differences between the two libraries.
You may find this information useful if you are an ioredis
user and you want to
start a new Node.js project or migrate an existing ioredis
project to node-redis
.
Comparison of ioredis
and node-redis
The tables below summarize how ioredis
and node-redis
implement some
key features of Redis. See the following sections for more information about
each feature.
Connection
Feature | ioredis |
node-redis |
---|---|---|
Initial connection | Happens when you create a client instance | Requires you to call a method on the client instance |
Reconnection after a connection is lost | Automatic by default | Manual by default |
Connection events | Emits connect , ready , error , and close events |
Emits connect , ready , error , end , and reconnecting events |
Command handling
Feature | ioredis |
node-redis |
---|---|---|
Command case | Lowercase only (eg, hset ) |
Uppercase or camel case (eg, HSET or hSet ) |
Command argument handling | Argument objects flattened and items passed directly | Argument objects parsed to generate correct argument list |
Asynchronous command result handling | Callbacks and Promises | Promises only |
Arbitrary command execution | Uses the call() method |
Uses the sendCommand() method |
Techniques
Feature | ioredis |
node-redis |
---|---|---|
Pipelining | Automatic, or with pipeline() command |
Automatic, or with multi() command |
Scan iteration | Uses scanStream() , etc |
Uses scanIterator() , etc |
Subscribing to channels | Uses client.on('message', ...) event |
Uses subscribe(...) command |
Specific commands
Command | ioredis |
node-redis |
---|---|---|
SETNX |
Supported explicitly | Supported as an option for SET |
HMSET |
Supported explicitly | Supported with standard HSET functionality |
CONFIG |
Supported explicitly | Supported with separate configGet() , configSet() , etc |
Details
The sections below explain the points of comparison between ioredis
and
node-redis
in more detail.
Initial connection
ioredis
makes the connection to the Redis server when you create an instance
of the client object:
const client = require('ioredis');
// Connects to localhost:6379 on instantiation.
const client = new Redis();
node-redis
requires you to call the connect()
method on the client object
to make the connection:
import { createClient } from 'redis';
const client = await createClient();
await client.connect(); // Requires explicit connection.
Reconnection after a connection is lost
ioredis
automatically attempts to reconnect if the connection
was lost due to an error. By default, node-redis
doesn't attempt
to reconnect, but you can enable a custom reconnection strategy
when you create the client object. See
Reconnect after disconnection
for more information.
Connection events
The connect
, ready
, error
, and close
events that ioredis
emits
are equivalent to the connect
, ready
, error
, and end
events
in node-redis
, but node-redis
also emits a reconnecting
event.
See Connection events
for more information.
Command case
Command methods in ioredis
are always lowercase. With node-redis
, you can
use uppercase or camel case versions of the method names.
// ioredis
client.hset('key', 'field', 'value');
// node-redis
client.HSET('key', 'field', 'value');
// ...or
client.hSet('key', 'field', 'value');
Command argument handling
ioredis
parses command arguments to strings and then passes them to
the server, in a similar way to redis-cli
.
// Equivalent to the command line `SET key 100 EX 10`.
client.set('key', 100, 'EX', 10);
Arrays passed as arguments are flattened into individual elements and objects are flattened into sequential key-value pairs:
// These commands are all equivalent.
client.hset('user' {
name: 'Bob',
age: 20,
description: 'I am a programmer',
});
client.hset('user', ['name', 'Bob', 'age', 20, 'description', 'I am a programmer']);
client.hset('user', 'name', 'Bob', 'age', 20, 'description', 'I am a programmer');
node-redis
uses predefined formats for command arguments. These include specific
classes for commmand options that generally don't correspond to the syntax
of the CLI command. Internally, node-redis
constructs the correct command using
the method arguments you pass:
// Equivalent to the command line `SET bike:5 bike EX 10`.
client.set('bike:5', 'bike', {EX: 10});
Asynchronous command result handling
All commands for both ioredis
and node-redis
are executed
asynchronously. ioredis
supports both callbacks and
Promise
return values to respond to command results:
// Callback
client.get('mykey', (err, result) => {
if (err) {
console.error(err);
} else {
console.log(result);
}
});
// Promise
client.get('mykey').then(
(result) => {
console.log(result);
},
(err) => {
console.error(err);
}
);
node-redis
supports only Promise
objects for results, so
you must always use a then()
handler or the
await
operator to receive them.
Arbitrary command execution
ioredis
lets you issue arbitrary commands in a similar format to
redis-cli
using the call()
command:
await client.call('JSON.SET', 'doc', "$", '{"f1": {"a":1}, "f2":{"a":2}}');
In node-redis
, you can get the same effect outside a transaction using sendCommand()
:
await client.sendCommand(['hset', 'hash2', 'number', '3']);
Within a transaction, use addCommand()
to include arbitrary commands. Note that
you can freely mix addCommand()
calls with standard commands in the same
transaction:
const responses = await client.multi()
.addCommand(['hset', 'hash3', 'number', '4'])
.hGet('hash3', 'number')
.exec();
Pipelining
Both ioredis
and node-redis
will pipeline commands automatically if
they are executed in the same "tick" of the
event loop
(see
Execute a pipeline
for more information).
You can also create a pipeline with explicit commands in both clients.
With ioredis
, you use the pipeline()
command with a chain of
commands, ending with exec()
to run the pipeline:
// ioredis example
client.pipeline()
.set('foo', '1')
.get('foo')
.set('foo', '2')
.incr('foo')
.get('foo')
.exec(function (err, results) {
// Handle results or errors.
});
For node-redis
, the approach is similar, except that you call the multi()
command to start the pipeline and execAsPipeline()
to run it:
client.multi()
.set('seat:3', '#3')
.set('seat:4', '#4')
.set('seat:5', '#5')
.execAsPipeline()
.then((results) => {
// Handle array of results.
},
(err) => {
// Handle errors.
});
Scan iteration
ioredis
supports the scanStream()
method to create a readable stream
from the set of keys returned by the SCAN
command:
const client = new Redis();
// Create a readable stream (object mode)
const stream = client.scanStream();
stream.on('data', (resultKeys) => {
// `resultKeys` is an array of strings representing key names.
// Note that resultKeys may contain 0 keys, and that it will sometimes
// contain duplicates due to SCAN's implementation in Redis.
for (let i = 0; i < resultKeys.length; i++) {
console.log(resultKeys[i]);
}
});
stream.on('end', () => {
console.log('all keys have been visited');
});
You can also use the similar hscanStream()
, sscanStream()
, and
zscanStream()
to iterate over the items of a hash, set, or sorted set,
respectively.
node-redis
handles scan iteration using the scanIterator()
method
(and the corresponding hscanIterator()
, sscanIterator()
, and
zscanIterator()
methods). These return a collection object for
each page scanned by the cursor (this can be helpful to improve
efficiency using MGET
and
other multi-key commands):
for await (const keys of client.scanIterator()) {
const values = await client.mGet(keys);
// Process values...
}
Subscribing to channels
ioredis
reports incoming pub/sub messages with a message
event on the client object (see
Publish/subscribe for more
information about messages):
client.on('message', (channel, message) => {
console.log(Received message from ${channel}: ${message});
});
With node-redis
, you use the subscribe()
command to register the
message callback. Also, when you use a connection to subscribe, that
connection can't issue any other commands, so you must create a
dedicated connection for the subscription. Use the client.duplicate()
method to create a new connection with the same settings as the original:
const subscriber = client.duplicate();
await subscriber.connect();
await subscriber.subscribe('channel', (message) => {
console.log(Received message: ${message});
});
SETNX
command
ioredis
implements the SETNX
command with an explicit method:
client.setnx('bike:1', 'bike');
node-redis
doesn't provide a SETNX
method but implements the same
functionality with the NX
option to the SET
command:
await client.set('bike:1', 'bike', {'NX': true});
HMSET
command
The HMSET
command has been deprecated
since Redis v4.0.0, but it is still supported by ioredis
. With node-redis
you should use the HSET
command with
multiple key-value pairs. See the HSET
command page for more information.
CONFIG
command
ioredis
supports a config()
method to set or get server configuration
options:
client.config('SET', 'notify-keyspace-events', 'KEA');
node-redis
doesn't have a config()
method, but instead supports the
standard commands configSet()
,
configGet()
,
configResetStat()
, and
configRewrite
:
await client.configSet('maxclients', '2000');