vslru-cache.
The Canonical LRU vs a Batteries-Included Cache
at a glance.
Compare lru-cache and @humanspeak/memory-cache: the canonical LRU implementation against a TypeScript cache that layers wildcard invalidation, lifecycle hooks, statistics, and a @cached decorator on top of LRU + TTL.
side-by-side.
Every surface that matters, compared without spin.
| feature | @humanspeak/memory-cache | lru-cache |
|---|---|---|
| Zero Dependencies | yes | yes |
| TypeScript Support | Written in TypeScript | Written in TypeScript |
| LRU Eviction lru-cache is the canonical, heavily tuned implementation. Memory Cache prunes expired entries before evicting any valid least-recently-used key. | yes | yes |
| TTL Expiration lru-cache also supports allowStale and updateAgeOnGet for finer recency/staleness control. | Per cache instance | Per cache + per-entry overrides |
| Size-Aware Eviction Both accept a user-supplied calculator. Memory Cache exposes aggregate weight in getStats(); lru-cache has broader size and disposal tuning. | Entry count + computed weight (maxSize + maxWeight / sizeCalculation) | Entry count + computed size (max + maxSize / sizeCalculation) |
| Wildcard / Prefix Deletion | deleteByMagicString + deleteByPrefix | no |
| Method Memoization Decorator | @cached, async-aware | memo() method (no decorator) |
| Async Fetch De-Duplication | getOrSet() collapses concurrent lookups | fetch() with fetchMethod |
| Stale-While-Revalidate | no | allowStale + background fetch |
| Lifecycle Instrumentation | Six lifecycle hooks | dispose / onInsert callbacks |
| Built-In Statistics | getStats() aggregate counters | Opt-in per-call status tracking |
| Browser Support | yes | yes |
where each shines.
- +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
- +The canonical LRU — extremely optimized and battle-tested at npm scale
- +Broader size-calculation, disposal, and tuning controls
- +Stale-while-revalidate patterns with allowStale and async fetch()
- +Rich low-level controls (peek, dispose, updateAgeOnGet, per-entry TTL)
where each falls short.
- −Smaller community (newer project)
- −In-process only — no persistence or multi-process sharing by design
- −TTL is configured per cache instance, not per entry
- −Lower-level API with many knobs to hold correctly
- −No wildcard or prefix bulk invalidation
- −Memoization is a method helper, not a decorator you can put on class methods
- −No aggregate hit/miss statistics or lifecycle hook set out of the box
the honest call.
Both libraries can enforce application-defined computed-weight bounds; neither automatically measures retained JavaScript heap. If your bottleneck is raw LRU throughput or you need stale-while-revalidate and extensive low-level tuning, lru-cache remains the reference implementation. Memory Cache adds a @cached decorator, wildcard invalidation, lifecycle hooks, and aggregate stats with a smaller API surface. Pick lru-cache for infrastructure-grade controls; pick Memory Cache when you want application-level caching that reads like TypeScript.
read more.
Every head-to-head, with the same matrix + pros / cons + verdict format.
memory cache → install in 30 seconds