mrkeyoor.com_
Sat 08 Aug 21:01 UTC
npmUtilsupdated 08 Aug 2026

weak-lru-cache

weak-lru-cache is an in-memory JavaScript cache that combines a strongly retained least-recently and frequently used window with WeakRef storage after an object ages out of that window. Recently used objects stay predictable; older objects may remain retrievable until the garbage collector reclaims them. It is designed for object identity reuse and memory-sensitive memoization, not for TTL expiry, persistence, cross-process sharing, or exact capacity guarantees.

Verdict

A clever fit for recreatable object graphs whose cold values may vanish whenever the runtime chooses. Most application caches need deterministic limits or TTLs instead, and should install lru-cache rather than accept weak-reference semantics and a surprising Map interface.

API stability4/5Version 1.2.2 exposes a small constructor plus getValue and setValue, and the source has not changed since 2022. ESM and CommonJS entry points are declared explicitly. The main risk is semantic rather than churn: inherited Map methods operate on CacheEntry objects, and the bundled declaration disagrees with runtime source about setValue's return value, so some apparent API is accidental.
Docs3/5The README explains the two-phase strong-to-weak model, primitive handling, cacheSize, custom expirer, weak-only mode, deferred registration, pinning, and the difference between get and getValue. It has no full API reference for deletion, clearing, statistics, or iteration, and its opening setup sample uses an undefined myValue variable plus non-JavaScript arrow notation.
Maintenance2/5The npm release 1.2.2 dates to February 2, 2022, and GitHub's last push is April 2, 2022. The repository is not archived and has only 2 open issues and pull requests, but four years without a release or push means there is no recent runtime matrix, type correction, or evidence that behavior has been checked against current Node and browser engines.
Ecosystem3/5The package recorded 5,089,270 downloads in the measured week, largely reflecting its role in dependency trees, and it works without runtime dependencies. Its direct footprint is niche at 39 GitHub stars, with no documented plugin ecosystem or framework integrations. Weak cache semantics also make it less interchangeable with the much larger family of TTL and bounded LRU packages.

Use it if

  • You cache recreatable object values and want memory pressure to decide when cold entries finally disappear
  • You need to return the same object identity for a key while that object remains alive elsewhere
  • You run Node 14.10 or newer, or another runtime with WeakRef and FinalizationRegistry support
  • You can tolerate cache misses at nondeterministic times and will always recompute safely
Skip it if

Setup reality

There are no dependencies, peers, native builds, credentials, or config files: install weak-lru-cache and import WeakLRUCache. Runtime support is the first real gate. The README requires Node 14.10 or newer, unless using the old Node 13 harmony flag, because the implementation constructs WeakRef and FinalizationRegistry immediately. The package provides ESM and CommonJS entries and a small index.d.ts, but that declaration says setValue returns void while the implementation returns a CacheEntry, so do not build typed code around the runtime return value. The biggest surprise is its Map inheritance. setValue and getValue are the intended value API; inherited get returns the internal WeakRef-like CacheEntry, iteration yields entries rather than values, and inherited set expects one of those internal entries rather than an ordinary object. Objects start with a strong reference inside the LRFU expirer, then fall back to a weak reference after expiration; collection after that is nondeterministic. Primitives cannot take the weak phase. cacheSize defaults to 32,768 and accepts at most 16,777,216 according to the README, but it controls the strong retention machinery rather than an exact object ceiling. A shared expirer is the default across cache instances. Pass expirer: false for weak-only behavior, use a custom LRFUExpirer only when you understand that cross-cache retention tradeoff, and never write tests that force or time garbage collection as correctness behavior.

Patterns

Store and retrieve an objectcache-object

import { WeakLRUCache } from 'weak-lru-cache';

const cache = new WeakLRUCache();
cache.setValue('user:42', { id: 42, name: 'Ada' });
const user = cache.getValue('user:42');

The object is strongly retained while active, then weakly retained after LRFU expiration and may disappear after garbage collection.

Recreate a value after a cache missfill-on-miss

async function getUser(id) {
  const key = `user:${id}`;
  let user = cache.getValue(key);
  if (user === undefined) {
    user = await database.loadUser(id);
    cache.setValue(key, user);
  }
  return user;
}

A miss is always possible, even if the key was stored earlier, so recomputation must be safe and expected.

Intern objects by a stable keypreserve-object-identity

function internNode(id, fields) {
  const existing = cache.getValue(id);
  if (existing) return existing;
  const node = Object.freeze({ id, ...fields });
  cache.setValue(id, node);
  return node;
}

Identity is preserved only while the object remains cached or strongly referenced elsewhere; it is not permanent interning.

Tune the strong retention cacheset-cache-size

import { WeakLRUCache } from 'weak-lru-cache';

const cache = new WeakLRUCache({
  cacheSize: 4096,
});

cacheSize tunes the LRFU retention structure, not an exact cap on weakly reachable objects or memory bytes.

Expire a large object soonerweight-large-value

const bytes = Buffer.byteLength(JSON.stringify(document));
cache.setValue(document.id, document, bytes >> 10);

Higher expirationPriority values expire sooner. The README suggests approximate kilobytes as a relative weight, not as byte-accurate accounting.

Pin a value in strong memorypin-value

cache.setValue('schema', compiledSchema, -1);

A negative expiration priority pins the entry until it is changed; pinning defeats the memory-release reason for choosing a weak cache.

Replace a pinned value with normal retentionunpin-value

const current = cache.getValue('schema');
if (current) {
  cache.setValue('schema', current, 0);
}

Calling getValue alone keeps a pinned entry pinned. Replace it with a nonnegative priority to return it to normal expiration.

Disable the strong LRFU layeruse-weak-only-mode

const weakOnly = new WeakLRUCache({
  expirer: false,
});
weakOnly.setValue('preview', previewObject);

With no strong retention cache, values may become collectible as soon as outside strong references disappear. Primitive values are especially poor fits.

Give one cache a separate expirerisolate-expiration-policy

import { LRFUExpirer, WeakLRUCache } from 'weak-lru-cache';

const expirer = new LRFUExpirer({
  lruSize: 2048,
  cleanupInterval: 30000,
});
const cache = new WeakLRUCache({ expirer });

The default expirer is shared. A private expirer isolates competition but gives up automatic priority across caches.

Remove an entry explicitlydelete-entry

const removed = cache.delete('user:42');

Explicit deletion is deterministic and also removes the entry from the expiration structure; do this for invalidation instead of waiting for GC.

Clear all entriesclear-cache

cache.clear();

clear removes entries from both the Map and the LRFU expirer, but objects can of course remain alive through references held elsewhere.

Inspect internal entry metadata deliberatelyinspect-cache-entry

const entry = cache.get('user:42');
const value = entry?.deref ? entry.deref() : entry?.value;

Inherited get returns a CacheEntry, not your cached value. Application code should normally call getValue and avoid depending on internal fields.

Alternatives

PackageRegistryPick it when
lru-cachenpmYou need maintained deterministic limits, TTLs, disposal hooks, and fetch-style cache filling
quick-lrunpmYou want a compact ESM LRU with a predictable maximum size and simple API
mnemonistnpmYou need a broader collection library that includes fixed-capacity LRU maps and caches