// the find
mcollina/async-cache-dedupe
Async cache with dedupe support
async-cache-dedupe solves a specific, annoying problem: when multiple concurrent callers request the same async resource, only one actual fetch happens and all callers get the same result. It's not just a cache — the deduplication is the point. Maintained by Matteo Collina (Fastify core, Node.js TSC), so it's not abandoned side-project quality.
The deduplication primitive is genuinely useful and not something you get for free from a plain LRU cache. The reference-based invalidation system lets you invalidate by logical entity ('user~1') rather than by reconstructing exact cache keys, which is the right model for apps with complex data dependencies. Per-resolver storage configuration means you can put hot/small lookups in memory and large/shared data in Redis without a wrapper. The 100%-coverage test requirement and browser CI across multiple bundlers suggests the library is actually tested against reality.
The Redis GC story is awkward — you have to wire up your own setInterval with lazy/strict modes, tune chunk sizes, and track the cursor yourself. This is too much ceremony for something that should just work. The TypeScript ergonomics are genuinely bad: defining functions mutates the cache object at runtime in a way the type system can't follow, so the chaining workaround in the docs is a smell, not a feature. Custom storage requires implementing a fairly wide interface (8 methods) with no partial-implementation support, which raises the bar for non-trivial backends. The stale-while-revalidate semantics aren't explicitly documented in terms of what happens when the background revalidation itself fails — you'd have to read the source to know if stale data stays live or gets evicted.