Simple key-value storage with support for multiple backends
Installations
npm install @keyv/redis
Developer Guide
Typescript
Yes
Module System
ESM
Min. Node Version
>= 18
Node Version
20.17.0
NPM Version
10.9.0
Score
99.2
Supply Chain
100
Quality
86.4
Maintenance
100
Vulnerability
100
License
Releases
Contributors
Languages
TypeScript (99.13%)
CSS (0.36%)
Shell (0.35%)
JavaScript (0.16%)
Developer
Download Statistics
Total Downloads
21,491,185
Last Day
46,965
Last Week
265,445
Last Month
792,808
Last Year
9,442,825
GitHub Statistics
2,711 Stars
1,450 Commits
156 Forks
19 Watching
2 Branches
69 Contributors
Bundle Size
288.56 kB
Minified
54.57 kB
Minified + Gzipped
Package Meta Information
Latest Version
4.2.0
Package Id
@keyv/redis@4.2.0
Unpacked Size
67.72 kB
Size
12.26 kB
File Count
7
NPM Version
10.9.0
Node Version
20.17.0
Publised On
21 Dec 2024
Total Downloads
Cumulative downloads
Total Downloads
21,491,185
Last day
-0.1%
46,965
Compared to previous day
Last week
5.7%
265,445
Compared to previous week
Last month
-7.7%
792,808
Compared to previous month
Last year
44.9%
9,442,825
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dependencies
3
Dev Dependencies
7
@keyv/redis
Redis storage adapter for Keyv
Redis storage adapter for Keyv.
Features
- Built on top of redis.
- TTL is handled directly by Redis.
- Supports Redis Clusters.
- Url connection string support or pass in your Redis Options
- Easily add in your own Redis client.
- Namespace support for key management.
- Unlink as default delete method for performance.
- Access to the Redis client for advanced use cases.
- Keyv and Redis Libraries are exported for advanced use cases.
createKeyv
function for easy creation of Keyv instances.- jsDoc comments for easy documentation.
- CJS / ESM and TypeScript supported out of the box.
Table of Contents
- Usage
- Namespaces
- Typescript
- Performance Considerations
- High Memory Usage on Redis Server
- Using Cacheable with Redis
- Clustering and TLS Support
- API
- Migrating from v3 to v4
- About Redis Sets and its Support in v4
- License
Usage
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', { namespace: 'my-namespace' });
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
:
1import Keyv from 'keyv'; 2import KeyvRedis, { createClient } from '@keyv/redis'; 3 4const redis = createClient('redis://user:pass@localhost:6379', { namespace: 'my-namespace'}); 5const keyvRedis = new KeyvRedis(redis); 6const keyv = new Keyv({ store: keyvRedis });
Namespaces
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:
1import Keyv from 'keyv'; 2import KeyvRedis from '@keyv/redis'; 3 4const keyv = new Keyv(new KeyvRedis('redis://user:pass@localhost:6379', { namespace: 'my-namespace' }));
This will prefix all keys with my-namespace:
. 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.
Typescript
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 5interface 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'
Performance Considerations
With namespaces being prefix based it is critical to understand some of the performance considerations we have made:
-
clear()
- We use theSCAN
command to iterate over keys. This is a non-blocking command that is more efficient thanKEYS
. In addition we are usingUNLINK
by default instead ofDEL
. Even with that if you are iterating over a large dataset it can still be slow. It is highly recommended to use thenamespace
option to limit the keys that are being cleared and if possible to not use theclear()
method in high performance environments. If you don't set namespaces, you can enablenoNamespaceAffectsAll
to clear all keys using theFLUSHDB
command which is faster and can be used in production environments. -
delete()
- By default we are now usingUNLINK
instead ofDEL
for deleting keys. This is a non-blocking command that is more efficient thanDEL
. If you are deleting a large number of keys it is recommended to use thedeleteMany()
method instead ofdelete()
. -
clearBatchSize
- TheclearBatchSize
option is set to1000
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 totrue
this option will be ignored and theFLUSHDB
command will be used instead. -
useUnlink
- This option is set totrue
by default. This is becauseUNLINK
is a non-blocking command that is more efficient thanDEL
. If you are not usingUNLINK
and are doing a lot of deletes it is recommended to set this option totrue
. -
setMany
,getMany
,deleteMany
- These methods are more efficient than their singular counterparts. These will be used by default in theKeyv
library such as when usingkeyv.delete(string[])
it will usedeleteMany()
.
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.
High Memory Usage on Redis Server
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;
Using Cacheable with Redis
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. 🚀
Clustering and TLS Support
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) });
API
- constructor([connection], [options])
- namespace - The namespace to use for the keys.
- client - The Redis client instance.
- keyPrefixSeparator - The separator to use between the namespace and key.
- clearBatchSize - The number of keys to delete in a single batch.
- useUnlink - Use the
UNLINK
command for deleting keys isntead ofDEL
. - noNamespaceAffectsAll: Whether to allow clearing all keys when no namespace is set (default is
false
). - set - Set a key.
- setMany - Set multiple keys.
- get - Get a key.
- getMany - Get multiple keys.
- has - Check if a key exists.
- hasMany - Check if multiple keys exist.
- delete - Delete a key.
- deleteMany - Delete multiple keys.
- clear - Clear all keys in the namespace. If the namespace is not set it will clear all keys that are not prefixed with a namespace unless
noNamespaceAffectsAll
is set totrue
. - disconnect - Disconnect from the Redis server.
- iterator - Create a new iterator for the keys. If the namespace is not set it will iterate over all keys that are not prefixed with a namespace unless
noNamespaceAffectsAll
is set totrue
.
Migrating from v3 to v4
Overall the API is the same as v3 with additional options and performance improvements. Here are the main changes:
- The
ioredis
library has been removed in favor of theredis
akanode-redis
library. If you want to use ioredis you can use@keyv/keyval
- The
useUnlink
option has been added to useUNLINK
instead ofDEL
and set to true by default. - The
clearBatchSize
option has been added to set the number of keys to delete in a single batch. - The
clear()
anddelete()
methods now useUNLINK
instead ofDEL
. If you want to useDEL
you can set theuseUnlink
option tofalse
. - BREAKING: 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.
- BREAKING: YOUR PREVIOUS KEYS WILL NOT BE VALID. This is because of the fixe of the namespace support and how it is handled. Now, when using
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
.
About Redis Sets and its Support in v4
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.
License
No vulnerabilities found.
Reason
security policy file detected
Details
- Info: security policy file detected: SECURITY.md:1
- Info: Found linked content: SECURITY.md:1
- Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1
- Info: Found text in security policy: SECURITY.md:1
Reason
30 commit(s) and 22 issue activity found in the last 90 days -- score normalized to 10
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
0 existing vulnerabilities detected
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: MIT License: LICENSE:0
Reason
SAST tool is run on all commits
Details
- Info: SAST configuration detected: CodeQL
- Info: all commits (23) are checked with a SAST tool
Reason
Found 7/30 approved changesets -- score normalized to 2
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql-analysis.yml:28
- Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql-analysis.yml:29
- Warn: no topLevel permission defined: .github/workflows/codecov.yaml:1
- Warn: no topLevel permission defined: .github/workflows/codeql-analysis.yml:1
- Warn: no topLevel permission defined: .github/workflows/deploy-website.yml:1
- Warn: no topLevel permission defined: .github/workflows/tests.yaml:1
- Info: no jobLevel write permissions found
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codecov.yaml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/codecov.yaml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codecov.yaml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/codecov.yaml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/codecov.yaml:39: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/codecov.yaml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/codeql-analysis.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:45: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/codeql-analysis.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:56: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/codeql-analysis.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:70: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/codeql-analysis.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/deploy-website.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/deploy-website.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/deploy-website.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/deploy-website.yml/main?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/deploy-website.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/deploy-website.yml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yaml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/tests.yaml/main?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yaml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/jaredwray/keyv/tests.yaml/main?enable=pin
- Warn: containerImage not pinned by hash: packages/postgres/Dockerfile.ssl:1: pin your Docker image by updating postgres:latest to postgres:latest@sha256:87ec5e0a167dc7d4831729f9e1d2ee7b8597dcc49ccd9e43cc5f89e808d2adae
- Warn: npmCommand not pinned by hash: .github/workflows/codecov.yaml:25
- Warn: npmCommand not pinned by hash: .github/workflows/deploy-website.yml:30
- Warn: npmCommand not pinned by hash: .github/workflows/tests.yaml:25
- Info: 0 out of 10 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 2 third-party GitHubAction dependencies pinned
- Info: 0 out of 1 containerImage dependencies pinned
- Info: 0 out of 3 npmCommand dependencies pinned
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'main'
- Warn: branch protection not enabled for branch 'v4'
Score
5.8
/10
Last Scanned on 2025-01-13
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More