Gathering detailed insights and metrics for @keyv/redis
Gathering detailed insights and metrics for @keyv/redis
Gathering detailed insights and metrics for @keyv/redis
Gathering detailed insights and metrics for @keyv/redis
Simple key-value storage with support for multiple backends
npm install @keyv/redis
Typescript
Module System
Min. Node Version
Node Version
NPM Version
99.4
Supply Chain
100
Quality
91.2
Maintenance
100
Vulnerability
100
License
TypeScript (99.34%)
Shell (0.3%)
CSS (0.25%)
JavaScript (0.11%)
Total Downloads
31,315,122
Last Day
15,423
Last Week
448,982
Last Month
1,832,727
Last Year
14,705,008
MIT License
2,955 Stars
1,693 Commits
182 Forks
20 Watchers
2 Branches
79 Contributors
Updated on Jul 31, 2025
Latest Version
5.0.0
Package Id
@keyv/redis@5.0.0
Unpacked Size
100.12 kB
Size
19.74 kB
File Count
7
NPM Version
11.4.2
Node Version
22.12.0
Published on
Jul 19, 2025
Cumulative downloads
Total Downloads
Last Day
24.7%
15,423
Compared to previous day
Last Week
2.8%
448,982
Compared to previous week
Last Month
5%
1,832,727
Compared to previous month
Last Year
81.3%
14,705,008
Compared to previous year
3
1
Redis storage adapter for Keyv
Redis storage adapter for Keyv.
createKeyv
function for easy creation of Keyv instances.1npm install --save keyv @keyv/redis
Here is a standard use case where we implement Keyv
and @keyv/redis
:
1import Keyv from 'keyv'; 2import KeyvRedis from '@keyv/redis'; 3 4const keyv = new Keyv(new KeyvRedis('redis://user:pass@localhost:6379')); 5keyv.on('error', handleConnectionError);
Here is the same example but with the Keyv
instance created with the createKeyv
function:
1import { createKeyv } from '@keyv/redis'; 2 3const keyv = createKeyv('redis://user:pass@localhost:6379');
You only have to import the @keyv/redis
library if you are using the createKeyv
function. 🎉 Otherwise, you can import Keyv
and @keyv/redis
independently.
Here you can pass in the Redis options directly:
1import Keyv from 'keyv'; 2import KeyvRedis from '@keyv/redis'; 3 4const redisOptions = { 5 url: 'redis://localhost:6379', // The Redis server URL (use 'rediss' for TLS) 6 password: 'your_password', // Optional password if Redis has authentication enabled 7 8 socket: { 9 host: 'localhost', // Hostname of the Redis server 10 port: 6379, // Port number 11 reconnectStrategy: (retries) => Math.min(retries * 50, 2000), // Custom reconnect logic 12 13 tls: false, // Enable TLS if you need to connect over SSL 14 keepAlive: 30000, // Keep-alive timeout (in milliseconds) 15 } 16}; 17 18const keyv = new Keyv(new KeyvRedis(redisOptions));
Or you can create a new Redis instance and pass it in with KeyvOptions
such as setting the store
:
1import Keyv from 'keyv'; 2import KeyvRedis, { createClient } from '@keyv/redis'; 3 4const redis = createClient('redis://user:pass@localhost:6379'); 5const keyvRedis = new KeyvRedis(redis); 6const keyv = new Keyv({ store: keyvRedis});
The major change from v4 to v5 is that we are now using v5 of the @redis/client
library which has a new API. This means that some methods have changed but it should be a drop-in replacement for most use cases.
You can pass in options to the KeyvRedis
constructor. Here are the available options:
1export type KeyvRedisOptions = { 2 /** 3 * Namespace for the current instance. 4 */ 5 namespace?: string; 6 /** 7 * Separator to use between namespace and key. 8 */ 9 keyPrefixSeparator?: string; 10 /** 11 * Number of keys to delete in a single batch. 12 */ 13 clearBatchSize?: number; 14 /** 15 * Enable Unlink instead of using Del for clearing keys. This is more performant but may not be supported by all Redis versions. 16 */ 17 useUnlink?: boolean; 18 19 /** 20 * Whether to allow clearing all keys when no namespace is set. 21 * If set to true and no namespace is set, iterate() will return all keys. 22 * Defaults to `false`. 23 */ 24 noNamespaceAffectsAll?: boolean; 25 26 /** 27 * This is used to throw an error if the client is not connected when trying to connect. By default, this is 28 * set to true so that it throws an error when trying to connect to the Redis server fails. 29 */ 30 throwOnConnectError?: boolean; 31 32 /** 33 * This is used to throw an error if at any point there is a failure. Use this if you want to 34 * ensure that all operations are successful and you want to handle errors. By default, this is 35 * set to false so that it does not throw an error on every operation and instead emits an error event 36 * and returns no-op responses. 37 * @default false 38 */ 39 throwOnErrors?: boolean; 40 41 /** 42 * Timeout in milliseconds for the connection. Default is undefined, which uses the default timeout of the Redis client. 43 * If set, it will throw an error if the connection does not succeed within the specified time. 44 * @default undefined 45 */ 46 connectionTimeout?: number; 47};
You can pass these options when creating a new KeyvRedis
instance:
1import Keyv from 'keyv'; 2import KeyvRedis from '@keyv/redis'; 3 4const keyvRedis = new KeyvRedis({ 5 namespace: 'my-namespace', 6 keyPrefixSeparator: ':', 7 clearBatchSize: 1000, 8 useUnlink: true, 9 noNamespaceAffectsAll: false, 10 connectTimeout: 200 11}); 12 13const keyv = new Keyv({ store: keyvRedis });
You can also set these options after the fact by using the KeyvRedis
instance properties:
1import {createKeyv} from '@keyv/redis'; 2 3const keyv = createKeyv('redis://user:pass@localhost:6379'); 4keyv.store.namespace = 'my-namespace';
createKeyv
functionThe createKeyv
function is a convenience function that creates a new Keyv
instance with the @keyv/redis
store. It automatically sets the useKeyPrefix
option to false
. Here is an example of how to use it:
1import { createKeyv } from '@keyv/redis'; 2const keyv = createKeyv('redis://user:pass@localhost:6379');
To use a namespace you can do it here and this will set Keyv up correctly to avoid the double namespace issue:
1import { createKeyv } from '@keyv/redis';
2const keyv = createKeyv('redis://user:pass@localhost:6379', {namespace: 'my-namespace'});
createKeyvNonBlocking
functionThe createKeyvNonBlocking
function is a convenience function that creates a new Keyv
instance with the @keyv/redis
store does what createKeyv
does but also disables throwing errors, removes the offline queue redis functionality, and reconnect strategy so that when used as a secondary cache in libraries such as cacheable it does not block the primary cache. This is useful when you want to use Redis as a secondary cache and do not want to block the primary cache on connection errors or timeouts when using nonBlocking
. Here is an example of how to use it:
1import { createKeyvNonBlocking } from '@keyv/redis'; 2const keyv = createKeyvNonBlocking('redis://user:pass@localhost:6379');
You can set a namespace for your keys. This is useful if you want to manage your keys in a more organized way. Here is an example of how to set a namespace
with the store
option:
1import Keyv from 'keyv';
2import KeyvRedis, { createClient } from '@keyv/redis';
3
4const redis = createClient('redis://user:pass@localhost:6379');
5const keyvRedis = new KeyvRedis(redis);
6const keyv = new Keyv({ store: keyvRedis, namespace: 'my-namespace', useKeyPrefix: false });
To make this easier, you can use the createKeyv
function which will automatically set the namespace
option to the KeyvRedis
instance:
1import { createKeyv } from '@keyv/redis';
2const keyv = createKeyv('redis://user:pass@localhost:6379', { namespace: 'my-namespace' });
This will prefix all keys with my-namespace:
and will also set useKeyPrefix
to false
. This is done to avoid double prefixing of keys as we transition out of the legacy behavior in Keyv. You can also set the namespace after the fact:
1keyv.namespace = 'my-namespace';
NOTE: If you plan to do many clears or deletes, it is recommended to read the Performance Considerations section.
If you are using Keyv
with @keyv/redis
as the storage adapter, you may notice that keys are being prefixed twice. This is because Keyv
has a default prefixing behavior that is applied to all keys. To fix this, you can set the useKeyPrefix
option to false
when creating the Keyv
instance:
1import Keyv from 'keyv'; 2import KeyvRedis from '@keyv/redis'; 3 4const keyv = new Keyv(new KeyvRedis('redis://user:pass@localhost:6379'), { useKeyPrefix: false });
To make this easier, you can use the createKeyv
function which will automatically set the useKeyPrefix
option to false
:
1import { createKeyv } from '@keyv/redis'; 2const keyv = createKeyv('redis://user:pass@localhost:6379');
When initializing KeyvRedis
, you can specify the type of the values you are storing and you can also specify types when calling methods:
1import Keyv from 'keyv'; 2import KeyvRedis, { createClient } from '@keyv/redis'; 3 4 5type User { 6 id: number 7 name: string 8} 9 10const redis = createClient('redis://user:pass@localhost:6379'); 11 12const keyvRedis = new KeyvRedis<User>(redis); 13const keyv = new Keyv({ store: keyvRedis }); 14 15await keyv.set("user:1", { id: 1, name: "Alice" }) 16const user = await keyv.get("user:1") 17console.log(user.name) // 'Alice' 18 19// specify types when calling methods 20const user = await keyv.get<User>("user:1") 21console.log(user.name) // 'Alice'
With namespaces being prefix based it is critical to understand some of the performance considerations we have made:
clear()
- We use the SCAN
command to iterate over keys. This is a non-blocking command that is more efficient than KEYS
. In addition we are using UNLINK
by default instead of DEL
. Even with that if you are iterating over a large dataset it can still be slow. It is highly recommended to use the namespace
option to limit the keys that are being cleared and if possible to not use the clear()
method in high performance environments. If you don't set namespaces, you can enable noNamespaceAffectsAll
to clear all keys using the FLUSHDB
command which is faster and can be used in production environments.
delete()
- By default we are now using UNLINK
instead of DEL
for deleting keys. This is a non-blocking command that is more efficient than DEL
. If you are deleting a large number of keys it is recommended to use the deleteMany()
method instead of delete()
.
clearBatchSize
- The clearBatchSize
option is set to 1000
by default. This is because Redis has a limit of 1000 keys that can be deleted in a single batch. If no namespace is defined and noNamespaceAffectsAll is set to true
this option will be ignored and the FLUSHDB
command will be used instead.
useUnlink
- This option is set to true
by default. This is because UNLINK
is a non-blocking command that is more efficient than DEL
. If you are not using UNLINK
and are doing a lot of deletes it is recommended to set this option to true
.
setMany
, getMany
, deleteMany
- These methods are more efficient than their singular counterparts. These will be used by default in the Keyv
library such as when using keyv.delete(string[])
it will use deleteMany()
.
If you want to see even better performance please see the Using Cacheable with Redis section as it has non-blocking and in-memory primary caching that goes along well with this library and Keyv.
This is because we are using UNLINK
by default instead of DEL
. This is a non-blocking command that is more efficient than DEL
but will slowly remove the memory allocation.
If you are deleting or clearing a large number of keys you can disable this by setting the useUnlink
option to false
. This will use DEL
instead of UNLINK
and should reduce the memory usage.
1const keyv = new Keyv(new KeyvRedis('redis://user:pass@localhost:6379', { useUnlink: false }));
2// Or
3keyv.useUnlink = false;
When using @keyv/redis
, it is important to handle connection errors gracefully. You can do this by listening to the error
event on the KeyvRedis
instance. Here is an example of how to do that:
1import Keyv from 'keyv'; 2import KeyvRedis from '@keyv/redis'; 3const keyv = new Keyv(new KeyvRedis('redis://user:pass@localhost:6379')); 4keyv.on('error', (error) => { 5 console.error('error', error); 6});
By default, the KeyvRedis
instance will throw an error
if the connection fails to connect. You can disable this behavior by setting the throwOnConnectError
option to false
when creating the KeyvRedis
instance. If you want this to throw you will need to also set the Keyv instance to throwOnErrors: true
:
1import Keyv from 'keyv'; 2import KeyvRedis from '@keyv/redis'; 3 4const keyv = new Keyv(new KeyvRedis('redis://bad-uri:1111', { throwOnConnectError: false })); 5keyv.throwOnErrors = true; // This will throw an error if the connection fails 6 7await keyv.set('key', 'value'); // this will throw the connection error only.
On get
, getMany
, set
, setMany
, delete
, and deleteMany
, if the connection is lost, it will emit an error and return a no-op value. You can catch this error and handle it accordingly. This is important to ensure that your application does not crash due to a lost connection to Redis.
If you want to handle connection errors, retries, and timeouts more gracefully, you can use the throwOnErrors
option. This will throw an error if any operation fails, allowing you to catch it and handle it accordingly:
There is a default Reconnect Strategy
if you pass in just a uri
connection string we will automatically create a Redis client for you with the following reconnect strategy:
1export const defaultReconnectStrategy = (attempts: number): number | Error => { 2 // Exponential backoff base: double each time, capped at 2s. 3 // Parentheses make it clear we do (2 ** attempts) first, then * 100 4 const backoff = Math.min((2 ** attempts) * 100, 2000); 5 6 // Add random jitter of up to ±50ms to avoid thundering herds: 7 const jitter = (Math.random() - 0.5) * 100; 8 9 return backoff + jitter; 10};
If you are wanting to see even better performance with Redis, you can use Cacheable which is a multi-layered cache library that has in-memory primary caching and non-blocking secondary caching. Here is an example of how to use it with Redis:
1import KeyvRedis from '@keyv/redis'; 2import Cacheable from 'cacheable'; 3 4const secondary = new KeyvRedis('redis://user:pass@localhost:6379'); 5 6const cache = new Cacheable( { secondary } );
For even higher performance you can set the nonBlocking
option to true
:
1const cache = new Cacheable( { secondary, nonBlocking: true } );
This will make it so that the secondary does not block the primary cache and will be very fast. 🚀
If you are using a Redis Cluster or need to use TLS, you can pass in the redisOptions
directly. Here is an example of how to do that:
1import Keyv from 'keyv'; 2import KeyvRedis, { createCluster } from '@keyv/redis'; 3 4const cluster = createCluster({ 5 rootNodes: [ 6 { 7 url: 'redis://127.0.0.1:7000', 8 }, 9 { 10 url: 'redis://127.0.0.1:7001', 11 }, 12 { 13 url: 'redis://127.0.0.1:7002', 14 }, 15 ], 16}); 17 18const keyv = new Keyv({ store: new KeyvRedis(cluster) });
You can learn more about the createCluster
function in the documentation at https://github.com/redis/node-redis/tree/master/docs.
Here is an example of how to use TLS:
1import Keyv from 'keyv';
2import KeyvRedis from '@keyv/redis';
3
4const tlsOptions = {
5 socket: {
6 host: 'localhost',
7 port: 6379,
8 tls: true, // Enable TLS connection
9 rejectUnauthorized: false, // Ignore self-signed certificate errors (for testing)
10
11 // Alternatively, provide CA, key, and cert for mutual authentication
12 ca: fs.readFileSync('/path/to/ca-cert.pem'),
13 cert: fs.readFileSync('/path/to/client-cert.pem'), // Optional for client auth
14 key: fs.readFileSync('/path/to/client-key.pem'), // Optional for client auth
15 }
16};
17
18const keyv = new Keyv({ store: new KeyvRedis(tlsOptions) });
1000
.UNLINK
command for deleting keys isntead of DEL
.false
).noNamespaceAffectsAll
is set to true
.Quit
command. If you set force
to true
it will force the disconnect.noNamespaceAffectsAll
is set to true
.Keyv by default supports the error
event across all storage adapters. If you want to listen to other events you can do so by accessing the client
property of the KeyvRedis
instance. Here is an example of how to do that:
1import {createKeyv} from '@keyv/redis'; 2 3const keyv = createKeyv('redis://user:pass@localhost:6379'); 4const redisClient = keyv.store.client; 5 6redisClient.on('connect', () => { 7 console.log('Redis client connected'); 8}); 9 10redisClient.on('reconnecting', () => { 11 console.log('Redis client reconnecting'); 12}); 13 14redisClient.on('end', () => { 15 console.log('Redis client disconnected'); 16});
Here are some of the events you can listen to: https://www.npmjs.com/package/redis#events
Overall the API is the same as v3 with additional options and performance improvements. Here are the main changes:
ioredis
library has been removed in favor of the redis
aka node-redis
library. If you want to use ioredis you can use @keyv/valkey
useUnlink
option has been added to use UNLINK
instead of DEL
and set to true by default.clearBatchSize
option has been added to set the number of keys to delete in a single batch.clear()
and delete()
methods now use UNLINK
instead of DEL
. If you want to use DEL
you can set the useUnlink
option to false
.keyv
with @keyv/redis
as the storage adapter you can do the following:1import Keyv from 'keyv';
2import KeyvRedis from '@keyv/redis';
3
4const redis = new KeyvRedis('redis://user:pass@localhost:6379');
5const keyv = new Keyv({ store: redis, namespace: 'my-namespace', useKeyPrefix: false });
This will make it so the storage adapter @keyv/redis
will handle the namespace and not the keyv
instance. If you leave it on it will just look duplicated like my-namespace:my-namespace:key
.
We no longer support redis sets. This is due to the fact that it caused significant performance issues and was not a good fit for the library.
No vulnerabilities found.