Gathering detailed insights and metrics for cache-manager
Gathering detailed insights and metrics for cache-manager
Gathering detailed insights and metrics for cache-manager
Gathering detailed insights and metrics for cache-manager
a robust, scalable, and maintained set of caching packages
npm install cache-manager
Typescript
Module System
Node Version
NPM Version
99.6
Supply Chain
99.5
Quality
91.7
Maintenance
100
Vulnerability
100
License
TypeScript (99.45%)
JavaScript (0.38%)
CSS (0.18%)
Total Downloads
316,197,949
Last Day
155,480
Last Week
2,384,730
Last Month
10,491,618
Last Year
99,973,537
MIT License
1,847 Stars
1,595 Commits
198 Forks
10 Watchers
2 Branches
93 Contributors
Updated on Aug 01, 2025
Latest Version
7.1.0
Package Id
cache-manager@7.1.0
Unpacked Size
52.47 kB
Size
11.67 kB
File Count
7
NPM Version
11.4.1
Node Version
20.17.0
Published on
Jul 30, 2025
Cumulative downloads
Total Downloads
Last Day
15.7%
155,480
Compared to previous day
Last Week
-2.4%
2,384,730
Compared to previous week
Last Month
1.7%
10,491,618
Compared to previous month
Last Year
46.4%
99,973,537
Compared to previous year
A cache module for NodeJS that allows easy wrapping of functions in cache, tiered caches, and a consistent interface.
nonBlocking
option that optimizes how the system handles multiple stores.We moved to using Keyv which are more actively maintained and have a larger community.
A special thanks to Tim Phan who took cache-manager
v5 and ported it to Keyv which is the foundation of v6. 🎉 Another special thanks to Doug Ayers who wrote promise-coalesce
which was used in v5 and now embedded in v6.
v7
has only one breaking change which is changing the return type from null
to undefined
when there is no data to return. This is to align with the Keyv API and to make it more consistent with the rest of the methods. Below is an example of how to migrate from v6
to v7
:
1import { createCache } from 'cache-manager'; 2 3const cache = createCache(); 4const result = await cache.get('key'); 5// result will be undefined if the key is not found or expired 6console.log(result); // undefined
v6
is a major update and has breaking changes primarily around the storage adapters. We have moved to using Keyv which are more actively maintained and have a larger community. Below are the changes you need to make to migrate from v5
to v6
. In v5
the memoryStore
was used to create a memory store, in v6
you can use any storage adapter that Keyv supports. Below is an example of how to migrate from v5
to v6
:
1import { createCache, memoryStore } from 'cache-manager'; 2 3// Create memory cache synchronously 4const memoryCache = createCache(memoryStore({ 5 max: 100, 6 ttl: 10 * 1000 /*milliseconds*/, 7}));
In v6
you can use any storage adapter that Keyv supports. Below is an example of using the in memory store with Keyv
:
1import { createCache } from 'cache-manager'; 2 3const cache = createCache();
If you would like to do multiple stores you can do the following:
1import { createCache } from 'cache-manager'; 2import { createKeyv } from 'cacheable'; 3import { createKeyv as createKeyvRedis } from '@keyv/redis'; 4 5const memoryStore = createKeyv(); 6const redisStore = createKeyvRedis('redis://user:pass@localhost:6379'); 7 8const cache = createCache({ 9 stores: [memoryStore, redisStore], 10});
When doing in memory caching and getting errors on symbol
or if the object is coming back wrong like on Uint8Array
you will want to set the serialization
and deserialization
options in Keyv to undefined
as it will try to do json serialization.
1import { createCache } from "cache-manager"; 2import { Keyv } from "keyv"; 3 4const keyv = new Keyv(); 5keyv.serialize = undefined; 6keyv.deserialize = undefined; 7 8const memoryCache = createCache({ 9 stores: [keyv], 10});
The other option is to set the serialization to something that is not JSON.stringify
. You can read more about it here: https://keyv.org/docs/keyv/#custom-serializers
If you would like a more robust in memory storage adapter you can use CacheableMemory
from Cacheable. Below is an example of how to migrate from v5
to v6
using CacheableMemory
:
1import { createCache } from 'cache-manager'; 2import { createKeyv } from 'cacheable'; 3 4const cache = createCache({ 5 stores: [createKeyv({ ttl: 60000, lruSize: 5000 })], 6});
To learn more about CacheableMemory
please visit: http://cacheable.org/docs/cacheable/#cacheablememory---in-memory-cache
If you are still wanting to use the legacy storage adapters you can use the KeyvAdapter
to wrap the storage adapter. Below is an example of how to migrate from v5
to v6
using cache-manager-redis-yet
by going to Using Legacy Storage Adapters.
If you are looking for older documentation you can find it here:
CacheableMemory
or lru-cache
as storage adapterredis
and ioredis
Support1npm install cache-manager
By default, everything is stored in memory; you can optionally also install a storage adapter; choose one from any of the storage adapters supported by Keyv:
1npm install @keyv/redis 2npm install @keyv/memcache 3npm install @keyv/mongo 4npm install @keyv/sqlite 5npm install @keyv/postgres 6npm install @keyv/mysql 7npm install @keyv/etcd
In addition Keyv supports other storage adapters such as lru-cache
and CacheableMemory
from Cacheable (more examples below). Please read Keyv document for more information.
1import { Keyv } from 'keyv'; 2import { createCache } from 'cache-manager'; 3 4// Memory store by default 5const cache = createCache() 6 7// Single store which is in memory 8const cache = createCache({ 9 stores: [new Keyv()], 10})
Here is an example of doing layer 1 and layer 2 caching with the in-memory being CacheableMemory
from Cacheable and the second layer being @keyv/redis
:
1import { Keyv } from 'keyv';
2import KeyvRedis from '@keyv/redis';
3import { CacheableMemory } from 'cacheable';
4import { createCache } from 'cache-manager';
5
6// Multiple stores
7const cache = createCache({
8 stores: [
9 // High performance in-memory cache with LRU and TTL
10 new Keyv({
11 store: new CacheableMemory({ ttl: 60000, lruSize: 5000 }),
12 }),
13
14 // Redis Store
15 new Keyv({
16 store: new KeyvRedis('redis://user:pass@localhost:6379'),
17 }),
18 ],
19})
Once it is created, you can use the cache object to set, get, delete, and wrap functions in cache.
1 2// With default ttl and refreshThreshold 3const cache = createCache({ 4 ttl: 10000, 5 refreshThreshold: 3000, 6}) 7 8await cache.set('foo', 'bar') 9// => bar 10 11await cache.get('foo') 12// => bar 13 14await cache.del('foo') 15// => true 16 17await cache.get('foo') 18// => null 19 20await cache.wrap('key', () => 'value') 21// => value
Because we are using Keyv, you can use any storage adapter that Keyv supports such as lru-cache
or CacheableMemory
from Cacheable. Below is an example of using CacheableMemory
:
In this example we are using CacheableMemory
from Cacheable which is a fast in-memory cache that supports LRU and and TTL expiration.
1import { createCache } from 'cache-manager'; 2import { Keyv } from 'keyv'; 3import { KeyvCacheableMemory } from 'cacheable'; 4 5const store = new KeyvCacheableMemory({ ttl: 60000, lruSize: 5000 }); 6const keyv = new Keyv({ store }); 7const cache = createCache({ stores: [keyv] });
Here is an example using lru-cache
:
1import { createCache } from 'cache-manager'; 2import { Keyv } from 'keyv'; 3import { LRU } from 'lru-cache'; 4 5const keyv = new Keyv({ store: new LRU({ max: 5000, maxAge: 60000 }) }); 6const cache = createCache({ stores: [keyv] });
stores?: Keyv[]
List of Keyv instance. Please refer to the Keyv document for more information.
ttl?: number - Default time to live in milliseconds.
The time to live in milliseconds. This is the maximum amount of time that an item can be in the cache before it is removed.
refreshThreshold?: number | (value:T) => number - Default refreshThreshold in milliseconds. You can also provide a function that will return the refreshThreshold based on the value.
If the remaining TTL is less than refreshThreshold, the system will update the value asynchronously in background.
refreshAllStores?: boolean - Default false
If set to true, the system will update the value of all stores when the refreshThreshold is met. Otherwise, it will only update from the top to the store that triggered the refresh.
nonBlocking?: boolean - Default false
If set to true, the system will not block when multiple stores are used. Here is how it affects the type of functions:
set and mset
- will not wait for all stores to finish.get and mget
- will return the first (fastest) value found.del and mdel
- will not wait for all stores to finish.clear
- will not wait for all stores to finish.wrap
- will do the same as get
and set
(return the first value found and not wait for all stores to finish).cacheId?: string - Defaults to random string
Unique identifier for the cache instance. This is primarily used to not have conflicts when using wrap
with multiple cache instances.
set(key, value, [ttl]): Promise<value>
Sets a key value pair. It is possible to define a ttl (in milliseconds). An error will be throw on any failed
1await cache.set('key-1', 'value 1') 2 3// expires after 5 seconds 4await cache.set('key 2', 'value 2', 5000)
See unit tests in test/set.test.ts
for more information.
mset(keys: [ { key, value, ttl } ]): Promise<true>
Sets multiple key value pairs. It is possible to define a ttl (in milliseconds). An error will be throw on any failed
1await cache.mset([ 2 { key: 'key-1', value: 'value 1' }, 3 { key: 'key-2', value: 'value 2', ttl: 5000 }, 4]);
get(key): Promise<value>
Gets a saved value from the cache. Returns a null if not found or expired. If the value was found it returns the value.
1await cache.set('key', 'value') 2 3await cache.get('key') 4// => value 5 6await cache.get('foo') 7// => null
See unit tests in test/get.test.ts
for more information.
mget(keys: [key]): Promise<value[]>
Gets multiple saved values from the cache. Returns a null if not found or expired. If the value was found it returns the value.
1await cache.mset([ 2 { key: 'key-1', value: 'value 1' }, 3 { key: 'key-2', value: 'value 2' }, 4]); 5 6await cache.mget(['key-1', 'key-2', 'key-3']) 7// => ['value 1', 'value 2', null]
ttl(key): Promise<number | null>
Gets the expiration time of a key in milliseconds. Returns a null if not found or expired.
1await cache.set('key', 'value', 1000); // expires after 1 second 2 3await cache.ttl('key'); // => the expiration time in milliseconds 4 5await cache.get('foo'); // => null
See unit tests in test/ttl.test.ts
for more information.
del(key): Promise<true>
Delete a key, an error will be throw on any failed.
1await cache.set('key', 'value') 2 3await cache.get('key') 4// => value 5 6await cache.del('key') 7 8await cache.get('key') 9// => null
See unit tests in test/del.test.ts
for more information.
mdel(keys: [key]): Promise<true>
Delete multiple keys, an error will be throw on any failed.
1await cache.mset([ 2 { key: 'key-1', value: 'value 1' }, 3 { key: 'key-2', value: 'value 2' }, 4]); 5 6await cache.mdel(['key-1', 'key-2'])
clear(): Promise<true>
Flush all data, an error will be throw on any failed.
1await cache.set('key-1', 'value 1') 2await cache.set('key-2', 'value 2') 3 4await cache.get('key-1') 5// => value 1 6await cache.get('key-2') 7// => value 2 8 9await cache.clear() 10 11await cache.get('key-1') 12// => null 13await cache.get('key-2') 14// => null
See unit tests in test/clear.test.ts
for more information.
wrap(key, fn: async () => value, [ttl], [refreshThreshold]): Promise<value>
Alternatively, with optional parameters as options object supporting a raw
parameter:
wrap(key, fn: async () => value, { ttl?: number, refreshThreshold?: number, raw?: true }): Promise<value>
Wraps a function in cache. The first time the function is run, its results are stored in cache so subsequent calls retrieve from cache instead of calling the function.
If refreshThreshold
is set and the remaining TTL is less than refreshThreshold
, the system will update the value asynchronously. In the meantime, the system will return the old value until expiration. You can also provide a function that will return the refreshThreshold based on the value (value:T) => number
.
If the object format for the optional parameters is used, an additional raw
parameter can be applied, changing the function return type to raw data including expiration timestamp as { value: [data], expires: [timestamp] }
.
1await cache.wrap('key', () => 1, 5000, 3000) 2// call function then save the result to cache 3// => 1 4 5await cache.wrap('key', () => 2, 5000, 3000) 6// return data from cache, function will not be called again 7// => 1 8 9await cache.wrap('key', () => 2, { ttl: 5000, refreshThreshold: 3000, raw: true }) 10// returns raw data including expiration timestamp 11// => { value: 1, expires: [timestamp] } 12 13// wait 3 seconds 14await sleep(3000) 15 16await cache.wrap('key', () => 2, 5000, 3000) 17// return data from cache, call function in background and save the result to cache 18// => 1 19 20await cache.wrap('key', () => 3, 5000, 3000) 21// return data from cache, function will not be called 22// => 2 23 24await cache.wrap('key', () => 4, 5000, () => 3000); 25// return data from cache, function will not be called 26// => 4 27 28await cache.wrap('error', () => { 29 throw new Error('failed') 30}) 31// => error
NOTES:
ttl
is set for the key, the refresh mechanism will not be triggered.See unit tests in test/wrap.test.ts
for more information.
disconnect(): Promise<void>
Will disconnect from the relevant store(s). It is highly recommended to use this when using a Keyv storage adapter that requires a disconnect. For each storage adapter, the use case for when to use disconnect is different. An example is that @keyv/redis
should be used only when you are done with the cache.
1await cache.disconnect();
See unit tests in test/disconnect.test.ts
for more information.
cacheId(): string
Returns cache instance id. This is primarily used to not have conflicts when using wrap
with multiple cache instances.
stores(): Keyv[]
Returns the list of Keyv instances. This can be used to get the list of stores and then use the Keyv API to interact with the store directly.
1const cache = createCache({cacheId: 'my-cache-id'});
2cache.cacheId(); // => 'my-cache-id'
See unit tests in test/cache-id.test.ts
for more information.
Fired when a key has been added or changed.
1cache.on('set', ({ key, value, error }) => { 2 // ... do something ... 3})
Fired when a key has been removed manually.
1cache.on('del', ({ key, error }) => { 2 // ... do something ... 3})
Fired when the cache has been flushed.
1cache.on('clear', (error) => { 2 if (error) { 3 // ... do something ... 4 } 5})
Fired when the cache has been refreshed in the background.
1cache.on('refresh', ({ key, value, error }) => { 2 if (error) { 3 // ... do something ... 4 } 5})
See unit tests in test/events.test.ts
for more information.
You can use the stores
method to get the list of stores and then use the Keyv API to interact with the store directly. Below is an example of iterating over all stores and getting all keys:
1import Keyv from 'keyv'; 2import { createKeyv } from '@keyv/redis'; 3import { createCache } from 'cache-manager'; 4 5const keyv = new Keyv(); 6const keyvRedis = createKeyv('redis://user:pass@localhost:6379'); 7 8const cache = createCache({ 9 stores: [keyv, keyvRedis], 10}); 11 12// add some data 13await cache.set('key-1', 'value 1'); 14await cache.set('key-2', 'value 2'); 15 16// get the store you want to iterate over. In this example we are using the second store (redis) 17const store = cache.stores[1]; 18 19if(store?.iterator) { 20 for await (const [key, value] of store.iterator({})) { 21 console.log(key, value); 22 } 23}
WARNING: Be careful when using iterator
as it can cause major performance issues with the amount of data being retrieved. Also, Not all storage adapters support iterator
so you may need to check the documentation for the storage adapter you are using.
We will not be supporting cache-manager-ioredis-yet
or cache-manager-redis-yet
in the future as we have moved to using Keyv
as the storage adapter @keyv/redis
.
There are many storage adapters built for cache-manager
and because of that we wanted to provide a way to use them with KeyvAdapter
. Below is an example of using cache-manager-redis-yet
:
1import { createCache, KeyvAdapter } from 'cache-manager'; 2import { Keyv } from 'keyv'; 3import { redisStore } from 'cache-manager-redis-yet'; 4 5const adapter = new KeyvAdapter( await redisStore() ); 6const keyv = new Keyv({ store: adapter }); 7const cache = createCache({ stores: [keyv]});
This adapter will allow you to add in any storage adapter. If there are issues it needs to follow CacheManagerStore
interface.
If you would like to contribute to the project, please read how to contribute here CONTRIBUTING.md.
No vulnerabilities found.