FIG-001 · MASTHEAD
// compare / memory-cache vs vs-node-cache

vsnode-cache.

The Classic TTL Cache vs a Modern TypeScript Rewrite

FIG-001
SHEET 01 / 07
FIG-002 / OVERVIEW

at a glance.

Compare node-cache and @humanspeak/memory-cache: two in-memory TTL caches for Node.js with different answers on LRU eviction, value cloning, TypeScript support, bulk invalidation, and method memoization.

FIG-003 / FEATURE MATRIX

side-by-side.

Every surface that matters, compared without spin.

feature@humanspeak/memory-cachenode-cache
Zero Dependencies node-cache depends on clone because it deep-clones values on set and get by default (useClones), which also adds per-operation overhead.yesno
TypeScript Support Written in TypeScriptBundled typings
TTL Expiration node-cache lets ttl(key, ttl) override the default per key. Memory Cache sets one TTL per cache instance — create purpose-scoped caches for different lifetimes.Per cache instancestdTTL + per-key override
LRU Eviction When node-cache reaches maxKeys, set() throws ECACHEFULL instead of evicting. Memory Cache evicts the least recently used key after pruning expired entries.yesno
Bounded Memory maxSize with LRU evictionmaxKeys (set() throws when full)
Wildcard / Prefix Deletion deleteByMagicString + deleteByPrefixno
Method Memoization Decorator @cached, async-awareno
Async Fetch De-Duplication getOrSet() collapses concurrent lookupsno
Lifecycle Instrumentation Six lifecycle hooksEventEmitter events (set, del, expired, flush)
Built-In Statistics Both track hits and misses. node-cache adds rough key/value size estimates; Memory Cache adds eviction and expiration counters.yesyes
Browser Support yesNode-focused
Active Maintenance yesDormant (last release v5.1.2, 2020)
FIG-004 / STRENGTHS

where each shines.

▣ memory cache 8
  • +Zero runtime dependencies — works in Node and the browser
  • +TypeScript-first with fully typed generics (MemoryCache<T>)
  • +TTL expiration and true LRU eviction in one cache — expired entries are pruned before any valid key is evicted
  • +Wildcard + prefix bulk invalidation (deleteByMagicString, deleteByPrefix)
  • +@cached decorator for method-level memoization — async-aware with in-flight de-duplication
  • +getOrSet() async fetch helper that de-duplicates concurrent lookups for the same key
  • +Lifecycle hooks (onHit, onMiss, onSet, onDelete, onExpire, onEvict) plus built-in getStats()
  • +Synchronous reads and writes — no await on the hot path
▢ node-cache 4
  • +Battle-tested with a huge install base and years of production use
  • +Per-key TTL overrides (ttl, getTtl) and take() for read-and-delete
  • +Value cloning by default isolates cached data from later mutations
  • +Batch operations (mget, mset) out of the box
FIG-005 / LIMITATIONS

where each falls short.

▣ memory cache 3
  • Smaller community (newer project)
  • In-process only — no persistence or multi-process sharing by design
  • TTL is configured per cache instance, not per entry
▢ node-cache 4
  • No eviction policy — a full cache throws ECACHEFULL instead of making room
  • Deep-clones values on every set and get by default, a real cost for large objects
  • Dormant maintenance — no substantial release since 2020
  • No bulk invalidation, memoization decorator, or TypeScript-native API
FIG-006 / VERDICT

the honest call.

node-cache is the incumbent for a reason: it is simple, stable, and everywhere, and its per-key TTL overrides are genuinely handy. But it has been dormant since 2020, clones every value by default, and throws when full instead of evicting. If you want a bounded cache that manages its own memory, typed generics, wildcard invalidation, and a @cached decorator, Memory Cache is the modern replacement. If you only need a tiny TTL map and already depend on node-cache, there is no urgent reason to switch.

FIG-007 / MORE

read more.

Every head-to-head, with the same matrix + pros / cons + verdict format.

SET / JETBRAINS MONO + INTER
HUMANSPEAK · 2026
MIT LICENCE
try
memory cacheinstall in 30 seconds
SHEET 07 / 07
END OF DOCUMENT
↩ ALL COMPARISONS