quick-lru

A simple, fast Least Recently Used (LRU) cache built on a dual-Map design

Library
npm
v7.3.0
765stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
51/100Fair
Development Activity36
Maintenance24
Community56
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
75/100Good
Architecture74
Code Quality78
Innovation62
Learning Curve85

quick-lru is a minimal LRU (Least Recently Used) cache implemented as a Map subclass, so it supports the familiar get/set/has/delete interface plus iteration. It caps the cache at a configurable maxSize, evicting the least-recently-used entries once that size is exceeded, and optionally expires individual entries after a maxAge in milliseconds, with an onEviction callback for cleanup side effects like revoking object URLs.

Rather than the classic doubly-linked-list LRU implementation, quick-lru uses two internal Maps (a current cache and an ‘old’ cache) and rotates between them, avoiding the cost of relinking nodes on every access — trading a temporary cache size of up to 2 × maxSize for meaningfully faster reads and writes at scale.

What You Get

  • A QuickLRU class extending Map, so get, set, has, delete, keys, values, and iteration all work as expected
  • maxSize — evicts least-recently-used entries once the cache exceeds this bound
  • maxAge — optional global or per-entry (via set(key, value, {maxAge})) expiry in milliseconds, lazily checked on access
  • onEviction — a callback invoked right before an item is evicted due to size pressure, TTL expiration, or manual evict(), useful for cleanup like URL.revokeObjectURL
  • Full TypeScript type definitions (index.d.ts) shipped in the package

Common Use Cases

  • Bounding memory usage for an in-process cache of expensive computation results (parsed configs, compiled regexes, API responses)
  • Caching HTTP response data with a maxAge so entries expire automatically without a separate cleanup timer
  • Deduplicating repeated work in a request-handling pipeline (e.g. memoizing a lookup keyed by request parameters) with automatic eviction under load
  • Managing temporary browser resources like object URLs, using onEviction to revoke them exactly when they’re dropped from the cache

Under The Hood

Architecture - The entire implementation is one file (index.js, ~330 lines) defining QuickLRU extends Map with two private Map fields — #cache (the active generation) and #oldCache (the previous generation). Writes go into #cache; when #cache reaches maxSize, #oldCache is discarded, #cache is moved into #oldCache, and a fresh empty #cache is started — an O(1) rotation instead of relinking a doubly-linked list on every access. Reads check #cache first, then fall back to #oldCache and promote a hit back into #cache, which is what keeps recently-used items alive across rotations; this design is why the actual item count can temporarily reach up to double maxSize, a tradeoff the README calls out explicitly. Tech Stack - Zero runtime dependencies, pure ESM ("type": "module") using private class fields (#size, #cache, etc.) — a modern-JS-only implementation with no transpilation step; devDependencies are limited to ava (tests), nyc (coverage), tsd (type-definition tests), and xo (linting). Code Quality - test.js is over 1,100 lines covering eviction ordering, maxAge expiry (including per-entry overrides), onEviction firing semantics, and the documented dual-cache size behavior; index.test-d.ts runs tsd type-assertion tests against the shipped .d.ts file to catch type regressions, and xo (a strict ESLint preset) plus nyc coverage are wired into the single test script. API Design - Extending the native Map class means the public surface is instantly familiar — no new vocabulary to learn beyond the maxSize/maxAge/onEviction constructor options — and the algorithm section in the README transparently documents the size/performance tradeoff rather than hiding it, which is unusually forthcoming for a cache library and helps consumers decide if the up-to-2x memory ceiling is acceptable for their use case.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search