mrkeyoor.com_
Sat 08 Aug 20:58 UTC
npmDataupdated 08 Aug 2026

node-cache

node-cache is a synchronous, process-local key/value cache for Node.js. It stores everything in one JavaScript object, can clone values on set and get, expires entries with per-key or default TTLs, emits lifecycle events, and exposes simple hit and miss statistics. It feels a little like Memcached at the method level, but there is no server, persistence, networking, replication, or sharing between Node processes. The package is useful for small disposable caches inside one long-running process, and its own README puts the practical ceiling at about one million keys.

Verdict

Do not choose node-cache for a new distributed service: it is explicitly unmaintained and cannot share state between processes. It remains understandable and usable for a disposable cache in an older CommonJS application, but lru-cache is the safer default for new work.

API stability4/5The synchronous set, get, del, mget, mset, ttl, keys, stats, and event APIs have not moved since the 5.x line, and bundled declarations describe the same surface. That stability is partly inactivity rather than active compatibility work: callbacks are deprecated behind enableLegacyCallbacks, and the announced TypeScript-based v6 never arrived.
Docs3/5The README documents every option and public method with short examples, lists breaking changes by major version, explains cloning behavior, and calls out the approximate one-million-key practical limit. It also contains stale badges and references to an upcoming v6, and there is no maintained documentation site or deeper production guidance.
Maintenance1/5The project states plainly in its README that it is unmaintained and invites the community to maintain a fork. npm still serves version 5.1.2 from July 2020, the newest GitHub release entry is from 2019, and the repository was last pushed in June 2024. High download volume does not substitute for fixes or release ownership.
Ecosystem3/5The package still records 5,100,599 weekly downloads and has 2,372 GitHub stars, so examples, Stack Overflow answers, and transitive users are plentiful. Its API is self-contained and needs little integration work, but there is no meaningful adapter ecosystem because the cache is deliberately process-local, and newer cache packages now have the active community.

Use it if

  • You need a tiny synchronous cache inside one Node process and losing every entry on restart is acceptable
  • You want per-key TTLs, expiry events, bulk get and set, and basic hit and miss counters without running a cache server
  • You maintain CommonJS code and prefer require(), synchronous methods, and bundled TypeScript declarations
  • You need cached values cloned by default so callers cannot accidentally mutate the stored copy
Skip it if

Setup reality

Installation is only npm install node-cache, with no peer dependency, native build, credentials, service, or config file. Version 5.1.2 is CommonJS, so use require('node-cache') in CommonJS or a default interop import where your ESM and TypeScript setup supports it. The defaults deserve more attention than the install: stdTTL is 0, which means entries never expire; checkperiod is 600 seconds, so expired keys may remain allocated until accessed or swept; maxKeys is -1, so there is no entry cap; and useClones is true, so every set and get copies values. That cloning makes ordinary objects safer but costs CPU and can fail for values such as Promises. Setting useClones to false returns shared references, which is faster but allows callers to mutate cached state. A cache miss returns undefined, so storing undefined makes absence ambiguous. TTL arguments are seconds, while getTtl() returns an absolute millisecond timestamp, an easy unit mismatch. The cache is per process and disappears on restart, deploy, crash, worker recycle, or serverless cold start. With deleteOnExpire false, expired entries stay present and you are expected to handle the expired event yourself. Legacy callbacks must be explicitly enabled and were marked for removal in the never-released v6 rewrite. Call close() when lifecycle control matters, although the internal interval is unref'd and normally does not keep Node alive.

Patterns

Create a bounded cache with expiring entriescreate-cache

const NodeCache = require('node-cache');

const cache = new NodeCache({
  stdTTL: 300,
  checkperiod: 60,
  maxKeys: 10000,
});

stdTTL and checkperiod are seconds. The defaults are no TTL, a 600-second sweep, and no key limit.

Store and retrieve a valueset-and-get

cache.set('user:42', { name: 'Ada' }, 120);

const user = cache.get('user:42');
if (user === undefined) {
  console.log('cache miss');
}

A miss returns undefined, so do not store undefined if you need to distinguish a cached value from absence.

Use the cache-aside patterncache-aside

async function getUser(id) {
  const key = `user:${id}`;
  const cached = cache.get(key);
  if (cached !== undefined) return cached;

  const user = await db.users.findById(id);
  cache.set(key, user, 60);
  return user;
}

Concurrent misses can all call the database because node-cache has no built-in request coalescing or async loader.

Store several entries at onceset-many

cache.mset([
  { key: 'feature:a', val: true, ttl: 30 },
  { key: 'feature:b', val: false, ttl: 30 },
  { key: 'feature:c', val: true },
]);

Entries without ttl use stdTTL. mset returns true or throws when maxKeys would be exceeded.

Read several keysget-many

const values = cache.mget(['feature:a', 'feature:b']);

if (!Object.prototype.hasOwnProperty.call(values, 'feature:a')) {
  console.log('feature:a missed');
}

mget omits missing or expired keys and returns an object, not an array aligned to the requested keys.

Delete one or many entriesinvalidate-keys

const oneDeleted = cache.del('user:42');
const manyDeleted = cache.del(['user:43', 'user:44']);

console.log({ oneDeleted, manyDeleted });

del returns the number of entries actually removed; deleting a missing key is not an error.

Read and remove a one-time valuetake-once

cache.set('otp:session-7', '493102', 180);

const code = cache.take('otp:session-7');
if (code === undefined) throw new Error('expired or already used');

take is a synchronous get followed by deletion, but it is only atomic inside this one process and cannot coordinate multiple workers.

Inspect and extend an entry TTLinspect-ttl

const expiresAt = cache.getTtl('user:42');
if (expiresAt && expiresAt - Date.now() < 30_000) {
  cache.ttl('user:42', 120);
}

getTtl returns an absolute timestamp in milliseconds, 0 for no expiry, or undefined for a missing key; ttl() accepts seconds.

Observe expired entrieshandle-expiry

cache.on('expired', (key, value) => {
  console.log('expired', key, value);
});

Expiry listeners run in the same process. Keep handlers quick, and remember that process exit can happen before an entry expires.

Cache shared references for complex valuesavoid-cloning

const referenceCache = new NodeCache({
  stdTTL: 30,
  useClones: false,
});

referenceCache.set('client', databaseClient);

With useClones false, callers receive the original reference and can mutate it. This is required for Promises and many class instances.

Inspect cache hit and miss statisticsread-stats

const { keys, hits, misses, ksize, vsize } = cache.getStats();
const requests = hits + misses;
const hitRate = requests ? hits / requests : 0;
console.log({ keys, hitRate, ksize, vsize });

ksize and vsize are approximate byte counts, not enforceable memory limits. Use flushStats() to reset counters.

Clear data and stop the sweep intervalshutdown-cache

process.once('SIGTERM', () => {
  cache.flushAll();
  cache.close();
  process.exit(0);
});

flushAll removes all entries and close clears the checkperiod interval. Neither operation persists data for the next process.

Alternatives

PackageRegistryPick it when
lru-cachenpmUse it when you need actively maintained in-process caching with LRU eviction and size-based limits
quick-lrunpmUse it for a small ESM-first LRU cache with a strict maximum entry count
cache-managernpmUse it when you want a higher-level cache API and may later add shared stores such as Redis