ioredis review
ioredis 6.0.0 is a Node Redis client for standalone servers, Sentinel, and Cluster, with pipelines, transactions, scripts, Streams, Pub/Sub, and binary replies. The v6 major requires Node 20 and speaks RESP3 unless `protocol: 2` is set. It adds Redis 8.10 commands and managed HIMPORT fieldsets while correcting reconnect and cluster redirection cases. Our browser build failed on Node-only code. More importantly, the README calls maintenance best effort and tells new projects to choose node-redis.
ioredis 6.0.0 installed eight packages and 2 MB in 1.6 seconds on our box, passed npm audit, and could not bundle for a browser. Keep it for established Cluster, Sentinel, or pipeline behavior; for a new Node integration, follow the maintainers' recommendation and install node-redis.
We installed it
| Install | ✓ · 1.6s | 8 packages on disk · 2 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | n/a | could not be bundled for the browser (Node-only code, most likely) |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does ioredis install cleanly?
Yes. In a fresh container with an empty cache, npm install ioredis finished in 2 seconds, leaving 8 packages and 2 MB on disk. npm audit reported no known vulnerabilities.
Can ioredis run in a browser?
Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.
Does ioredis work with both ESM and CommonJS?
Yes. Both import 'ioredis' and require('ioredis') worked in Node 22 in our run. The package is published as CommonJS.
Does ioredis include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
ioredis or redis: which should you use?
redis: Start here for a new Node service, following the recommendation in ioredis's own README. ioredis 6.0.0 installed eight packages and 2 MB in 1.6 seconds on our box, passed npm audit, and could not bundle for a browser.
When should you not use ioredis?
This is a new Redis integration; the ioredis maintainers explicitly recommend node-redis and describe their own maintenance as best effort
Use it if
- An established Node service depends on ioredis retry, Cluster, Sentinel, or reply-transformer behavior
- Cluster pipelines, key-slot routing, Sentinel discovery, NAT mapping, or connection event controls are requirements
- The application uses scan streams, custom Lua commands, binary Pub/Sub, or explicit pipeline result tuples
- CommonJS is still required while TypeScript declarations and ESM consumption must also work
- This is a new Redis integration; the ioredis maintainers explicitly recommend node-redis and describe their own maintenance as best effort
- Execution targets a browser or edge isolate; esbuild could not resolve the Node facilities during our browser bundle attempt
- Production is on Node 18 or earlier; the 6.0.0 engine requirement starts at Node 20
- Existing code assumes RESP2 reply shapes; v6 defaults to RESP3 and needs `protocol: 2` as a migration setting
- Redis Stack commands and future Redis features must arrive quickly; the README points to node-redis for search, JSON, time series, and probabilistic structures
Setup reality
Our ioredis 6.0.0 install finished in 1.6 seconds under Node 22. It left eight packages totaling 2 MB, and npm audit returned zero known vulnerabilities. The ioredis archive is 1,588 KB unpacked with six direct dependencies and no peers. TypeScript declarations are included. Although the package is CommonJS and has no exports map, require() and ESM import both succeeded. esbuild could not make a browser bundle because the client relies on Node networking and runtime modules.
A local constructor defaults to port 6379, but production normally passes a redis:// or rediss:// URL carrying the ACL user, password, database, and TLS choice. Sentinel authentication uses sentinelPassword separately, and Sentinel TLS needs enableTLSForSentinelMode. Cluster discovery returns node addresses that your application must reach; managed networks may require dnsLookup or a NAT map. Version 6 requires Node 20 and defaults to RESP3.
Before the ready event, commands enter an offline queue unless you disable it. The default maxRetriesPerRequest fails a command after 20 reconnect attempts; setting it to null can leave the promise pending without a ceiling. Blocking consumers may accept that tradeoff, while HTTP handlers usually need short request deadlines. Version 6 fixes stale socket timeouts after reconnect and continues reconnecting when setup is interrupted, but it cannot supply an application-level timeout.
Once a connection subscribes, it can only manage subscriptions, ping, or quit, so publishing and normal commands require another client. Cluster multi-key work must resolve to one slot, often by using a shared hash tag inside braces. Auto-pipelining batches calls created within one event-loop turn. RESP3 can change reply shapes and transformer assumptions. Exercise pipelines, Pub/Sub, custom commands, and any managed Redis proxy before upgrading a v5 deployment.
Patterns
Connect with a Redis URL connect-url
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);
await redis.set('job:42', 'queued', 'EX', 300);
console.log(await redis.get('job:42'));Use rediss:// for TLS and keep credentials outside source control.
Store a JSON value with expiry set-json
await redis.set(
`session:${session.id}`,
JSON.stringify(session),
'EX',
1800,
);
const raw = await redis.get(`session:${session.id}`);
const saved = raw ? JSON.parse(raw) : null;Redis returns strings here. JSON parsing and schema validation remain application work.
Send commands in one pipeline pipeline-commands
const replies = await redis.pipeline()
.incr('metrics:requests')
.expire('metrics:requests', 60)
.get('metrics:requests')
.exec();
for (const [error, value] of replies) {
if (error) throw error;
console.log(value);
}Each result is an [error, value] pair; exec resolving does not mean every command succeeded.
Run a MULTI transaction atomic-transaction
const result = await redis.multi()
.decrby('account:1', 100)
.incrby('account:2', 100)
.exec();MULTI queues commands atomically, but business checks need WATCH or a Lua script to avoid races.
Use separate Pub/Sub connections publish-subscribe
const sub = new Redis(process.env.REDIS_URL);
const pub = new Redis(process.env.REDIS_URL);
await sub.subscribe('orders');
sub.on('message', (channel, message) => console.log(channel, message));
await pub.publish('orders', JSON.stringify({ id: 42 }));After subscribe(), that client enters subscriber mode and cannot issue normal Redis commands.
Iterate keys without KEYS scan-keys
const stream = redis.scanStream({ match: 'session:*', count: 200 });
for await (const keys of stream) {
if (keys.length) console.log(keys);
}SCAN may return duplicate keys and count is only a hint, so consumers must tolerate repeats.
Bound reconnect waiting configure-retries
const redis = new Redis(process.env.REDIS_URL, {
maxRetriesPerRequest: 2,
retryStrategy(times) {
return Math.min(times * 100, 2000);
},
});Returning null or undefined stops reconnecting. Setting maxRetriesPerRequest to null can leave commands pending indefinitely.
Connect to Redis Cluster connect-cluster
const cluster = new Redis.Cluster([
{ host: 'redis-1.internal', port: 6379 },
{ host: 'redis-2.internal', port: 6379 },
], { redisOptions: { password: process.env.REDIS_PASSWORD } });
await cluster.mget('{user:42}:name', '{user:42}:email');Multi-key commands require one hash slot. Matching text inside braces places these keys together.
Retain RESP2 during migration keep-resp2
const redis = new Redis(process.env.REDIS_URL, {
protocol: 2,
});
await redis.ping();Version 6 defaults to RESP3. Use this as a migration step, then test reply shapes before removing it.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| redis | npm | Start here for a new Node service, following the recommendation in ioredis's own README. |
| @redis/client | npm | Use the core node-redis package when optional Redis Stack module clients are unnecessary. |
| keyv | npm | Use it when application code needs a cache interface instead of Redis commands, Sentinel, or Cluster APIs. |
More data guides
numpy · fsspec · pandas · sqlalchemy · pyarrow · lxml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

