
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@cacheable/node-cache
Advanced tools
Simple and Maintained fast Node.js caching
@cacheable/node-cache is compatible with the node-cache package with regular maintenance and additional functionality (async/await and storage adapters) via {NodeCacheStore}. The only thing not implemented is the enableLegacyCallbacks option and functions. If you need them we are happy to take a PR to add them.
node-cache using {NodeCache}node-cache package 🚀{NodeCacheStore}@cacheable/utils for utilitiesnpm install @cacheable/node-cache --save
import NodeCache from '@cacheable/node-cache';
const cache = new NodeCache();
cache.set('foo', 'bar');
cache.get('foo'); // 'bar'
cache.set('foo', 'bar', 10); // 10 seconds
cache.del('foo'); // 1
cache.set('bar', 'baz', '35m'); // 35 minutes using shorthand
The NodeCache is not the default export, so you need to import it like this:
import {NodeCache} from '@cacheable/node-cache';
const cache = new NodeCache();
cache.set('foo', 'bar');
cache.get('foo'); // 'bar'
NodeCache also offers the ability to set the type of values that can be cached in Typescript environments.
import {NodeCache} from '@cacheable/node-cache';
const cache = new NodeCache<string>();
cache.set('foo', 'bar');
cache.get('foo'); // 'bar'
The performance is comparable if not faster to the original node-cache package, but with additional features and improvements.
| name | summary | ops/sec | time/op | margin | samples |
|---|---|---|---|---|---|
| Cacheable NodeCache - set / get | 🥇 | 117K | 9µs | ±1.01% | 111K |
| Node Cache - set / get | -4.6% | 112K | 9µs | ±1.31% | 106K |
constructor(options?: NodeCacheOptions)Create a new cache instance. You can pass in options to set the configuration:
export type NodeCacheOptions = {
stdTTL?: number | string;
checkperiod?: number;
useClones?: boolean;
deleteOnExpire?: boolean;
maxKeys?: number;
};
Here is a description of the options:
| Option | Default Setting | Description |
|---|---|---|
stdTTL | 0 | The standard time to live (TTL) in seconds for every generated cache element. If set to 0, it means unlimited. If a string is provided, it will be parsed as shorthand and default to milliseconds if it is a number as a string. |
checkperiod | 600 | The interval in seconds to check for expired keys. If set to 0, it means no periodic check will be performed. |
useClones | true | If set to true, the cache will clone the returned items via get() functions. This means that every time you set a value into the cache, node-cache makes a deep clone of it. When you get that value back, you receive another deep clone. This mimics the behavior of an external cache like Redis or Memcached, meaning mutations to the returned object do not affect the cached copy (and vice versa). If set to false, the original object will be returned, and mutations will affect the cached copy. |
deleteOnExpire | true | If set to true, the key will be deleted when it expires. If set to false, the key will remain in the cache, but the value returned by get() will be undefined. You can manage the key with the on('expired') event. |
maxKeys | -1 | If set to a positive number, it will limit the number of keys in the cache. If the number of keys exceeds this limit, it will throw an error when trying to set more keys than the maximum. If set to -1, it means unlimited keys are allowed. |
When initializing the cache you can pass in the options to set the configuration like the example below where we set the stdTTL to 10 seconds and checkperiod to 5 seconds.:
const cache = new NodeCache({stdTTL: 10, checkperiod: 5});
When setting deleteOnExpire to true it will delete the key when it expires. If you set it to false it will keep the key but the value on get() will be undefined. You can manage the key with on('expired') event.
const cache = new NodeCache({deleteOnExpire: false});
cache.on('expired', (key, value) => {
console.log(`Key ${key} has expired with value ${value}`);
});
set(key: string | number, value: any, ttl?: number | string): booleanSet a key value pair with an optional ttl (in seconds). Will return true on success. If the ttl is not set it will default to 0 (no ttl).
cache.set('foo', 'bar', 10); // true
mset(data: Array<PartialNodeCacheItem>): booleanSet multiple key value pairs at once. This will take an array of objects with the key, value, and optional ttl.
cache.mset([{key: 'foo', value: 'bar', ttl: 10}, {key: 'bar', value: 'baz'}]); // true
the PartialNodeCacheItem is defined as:
export type PartialNodeCacheItem = {
key: string | number;
value: any;
ttl?: number;
};
get<T>(key: string | number): T | undefinedGet a value from the cache by key. If the key does not exist it will return undefined.
cache.get('foo'); // 'bar'
mget<T>(keys: Array<string | number>): Record<string, T | undefined>Get multiple values from the cache by keys. This will return an object with the keys and values.
const obj = { my: 'value', my2: 'value2' };
const obj2 = { special: 'value3', life: 'value4' };
cache.set('my', obj);
cache.set('my2', obj2);
cache.mget(['my', 'my2']); // { my: { my: 'value', my2: 'value2' }, my2: { special: 'value3', life: 'value4' } }
take<T>(key: string | number): T | undefinedGet a value from the cache by key and delete it. If the key does not exist it will return undefined.
cache.set('foo', 'bar');
cache.take('foo'); // 'bar'
cache.get('foo'); // undefined
del(key: string | number | Array<string | number>): numberDelete a key from the cache. Will return the number of deleted entries and never fail. You can also pass in an array of keys to delete multiple keys. All examples assume that you have initialized the cache like const cache = new NodeCache();.
cache.del('foo'); // 1
passing in an array of keys:
cache.del(['foo', 'bar']); // 2
mdel(keys: Array<string | number>): numberDelete multiple keys from the cache. Will return the number of deleted entries and never fail.
cache.mdel(['foo', 'bar']); // 2
ttl(key: string | number, ttl?: number | string): booleanRedefine the ttl of a key. Returns true if the key has been found and changed. Otherwise returns false. If the ttl-argument isn't passed the default-TTL will be used.
cache.ttl('foo', 10); // true
getTtl(key: string | number): number | undefinedGet the ttl expiration from Date.now() of a key. If the key does not exist it will return undefined.
cache.getTtl('foo'); // 1725993344859
has(key: string | number): booleanCheck if a key exists in the cache.
cache.set('foo', 'bar');
cache.has('foo'); // true
keys(): string[]Get all keys from the cache.
cache.keys(); // ['foo', 'bar']
getStats(): NodeCacheStatsGet the stats of the cache.
cache.getStats(); // {hits: 1, misses: 1, keys: 1, ksize: 2, vsize: 3}
flushAll(): voidFlush the cache. Will remove all keys and reset the stats.
cache.flushAll();
cache.keys(); // []
cache.getStats(); // {hits: 0, misses: 0, keys: 0, ksize: 0, vsize: 0}
flushStats(): voidFlush the stats. Will reset the stats but keep the keys.
cache.set('foo', 'bar');
cache.flushStats();
cache.getStats(); // {hits: 0, misses: 0, keys: 0, ksize: 0, vsize: 0}
cache.keys(); // ['foo']
on(event: string, callback: Function): voidListen to events. Here are the events that you can listen to:
set - when a key is set and it will pass in the key and value.expired - when a key is expired and it will pass in the key and value.flush - when the cache is flushedflush_stats - when the stats are flusheddel - when a key is deleted and it will pass in the key and value.cache.on('set', (key, value) => {
console.log(`Key ${key} has been set with value ${value}`);
});
close(): voidClose the cache. This will stop the interval timeout which is set on the checkperiod option.
cache.close();
store: Map<string, NodeCacheItem<T>>The internal store is a public readonly Map that holds all cached items. Each item includes the key, value, and TTL expiration timestamp.
getIntervalId(): number | NodeJS.TimeoutGet the interval ID for the expiration checker.
startInterval(): voidStart the interval for checking expired keys based on the checkperiod option.
stopInterval(): voidStop the interval for checking expired keys.
NodeCacheStore has a similar API to NodeCache but it is using async / await as it uses Keyv under the hood. This means that you can use any storage adapter that is available in Keyv and it will work seamlessly with the NodeCacheStore. To learn more about the Keyv storage adapters you can check out the Keyv documentation.
import {NodeCacheStore} from '@cacheable/node-cache';
const cache = new NodeCacheStore();
await cache.set('foo', 'bar');
await cache.get('foo'); // 'bar'
Here is an example of how to use the NodeCacheStore with a Redis storage adapter:
import {NodeCacheStore} from '@cacheable/node-cache';
import Keyv from 'keyv';
import KeyvRedis from '@keyv/redis';
const keyv = new Keyv({store: new KeyvRedis('redis://user:pass@localhost:6379')});
const cache = new NodeCacheStore({store: keyv});
// with storage you have the same functionality as the NodeCache but will be using async/await
await cache.set('foo', 'bar');
await cache.get('foo'); // 'bar'
When initializing the cache you can pass in the options below:
export type NodeCacheStoreOptions = {
ttl?: number | string; // The standard ttl as number in milliseconds for every generated cache element. 0 = unlimited. Supports shorthand like '1h' for 1 hour.
store?: Keyv; // The storage adapter (defaults to in-memory Keyv)
};
Note: the ttl is now in milliseconds and not seconds like stdTTL in NodeCache. You can also use shorthand notation for TTL values. Here is an example:
const cache = new NodeCacheStore({ttl: 60000 }); // 1 minute as it defaults to milliseconds
await cache.set('foo', 'bar', '1h'); // 1 hour
await cache.set('longfoo', 'bar', '1d'); // 1 day
set(key: string | number, value: any, ttl?: number | string): Promise<boolean> - Set a key value pair with an optional ttl (in milliseconds or shorthand string). Will return true on success. If the ttl is not set it will default to the instance ttl or no expiration.mset(data: Array<PartialNodeCacheItem>): Promise<void> - Set multiple key value pairs at onceget<T>(key: string | number): Promise<T | undefined> - Get a value from the cache by keymget<T>(keys: Array<string | number>): Promise<Record<string, T | undefined>> - Get multiple values from the cache by keystake<T>(key: string | number): Promise<T | undefined> - Get a value from the cache by key and delete itdel(key: string | number): Promise<boolean> - Delete a keymdel(keys: Array<string | number>): Promise<boolean> - Delete multiple keysclear(): Promise<void> - Clear the cachesetTtl(key: string | number, ttl?: number | string): Promise<boolean> - Set the ttl of an existing keydisconnect(): Promise<void> - Disconnect the storage adapterttl: number | string | undefined - The standard ttl for every generated cache element. undefined = unlimitedstore: Keyv - The storage adapter (read-only)The main NodeCache class API has not changed and remains fully compatible. The primary internal change is that it now uses Keyv as the underlying store.
cache PropertynodeCache.cache returned a Cacheable instancenodeCache.store which returns a Keyv instanceprimary and secondary store options for multi-tier cachingstore option onlyMigration:
// V1
const cache = new NodeCacheStore({ primary: keyv1, secondary: keyv2 });
// V2 - use single store
const cache = new NodeCacheStore({ store: keyv });
If you need storage tiering functionality, use the cacheable package instead which supports primary and secondary stores.
@cacheable/utils instead of the cacheable package for a lighter footprintmaxKeys from NodeCacheStoreThe maxKeys option has been removed from NodeCacheStore. It does not make sense for a store backed by external services (Redis, MongoDB, etc.) where the backend manages its own capacity.
The maxKeys option remains available on the in-memory NodeCache class.
Migration:
// V2 - maxKeys was accepted but not meaningful for external stores
const cache = new NodeCacheStore({ maxKeys: 100 });
// V3 - remove maxKeys from NodeCacheStore options
const cache = new NodeCacheStore();
If you need key limits with an external store, configure the limit at the storage layer instead.
stats from NodeCacheStoreThe stats option and internal stats tracking have been removed from NodeCacheStore. The stats were collected internally but never exposed via a public API, making them effectively unused.
hookified to v2The underlying hookified dependency has been upgraded from v1 to v2. Both NodeCache and NodeCacheStore extend Hookified. Key changes in hookified v2:
logger property renamed to eventLoggerHook type renamed to HookFnonHook signature changed to handle IHook interfacethrowHookErrors configuration optionthrowOnEmptyListeners default changed to trueIf you use hooks or advanced event features from the Hookified base class directly, review the hookified v2 changelog for details.
You can contribute by forking the repo and submitting a pull request. Please make sure to add tests and update the documentation. To learn more about how to contribute go to our main README https://github.com/jaredwray/cacheable. This will talk about how to Open a Pull Request, Ask a Question, or Post an Issue.
FAQs
Simple and Maintained fast NodeJS internal caching
The npm package @cacheable/node-cache receives a total of 722,423 weekly downloads. As such, @cacheable/node-cache popularity was classified as popular.
We found that @cacheable/node-cache demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.