memorystore
A leak-free, LRU-backed session store for express-session, with configurable TTL and pruning.
Repository Health
Technical Analysis
memorystore replaces the default in-memory session store that ships with express-session, which has no way to expire old sessions and grows unbounded over the lifetime of a process. It wraps isaacs’s lru-cache behind the standard express-session Store interface, so every session write goes through a cache with a real max size and a real ttl, and expired or overflowed entries fall out automatically instead of accumulating.
Because it implements every required, recommended, and optional method of the express-session store contract (get, set, destroy, touch, all, length, clear, ids), it’s a drop-in swap for the default store in any existing Express app — the same session middleware setup, just with bounded memory. It adds a checkPeriod option to run a periodic sweep that proactively evicts expired sessions (disabled by default, since lru-cache already evicts lazily on access), plus prune(), startInterval(), and stopInterval() for manual control over that sweep from application code.
Sessions still live in a single process’s memory, so it isn’t a substitute for a shared store like Redis in a multi-process or multi-server deployment — it solves the leak, not the sharing problem. That tradeoff is exactly why it fits: single-instance apps, local development, and tests that want session support without standing up an external store.
What You Get
- A full express-session
Storeimplementation —get,set,destroy,touch,all,length,clear, andids— so it’s a drop-in replacement for the default store maxandttloptions that bound memory by cache size and session age, defaultingttlto the session cookie’smaxAgewhen one isn’t given- An optional periodic
checkPeriodsweep that proactively prunes expired sessions, plus a manualprune()method to trigger the same sweep on demand - A
disposecallback invoked when a session falls out of the cache, useful for cleanup work like closing file descriptors tied to a session - Pluggable
serializersupport (defaults toJSON) for controlling how session objects are stringified into the cache - TypeScript type definitions (
index.d.ts) describing the store’s options and shape out of the box
Common Use Cases
- Adding session support to a single-instance Express app without needing to run Redis or another external store
- Local development and CI test environments where a lightweight in-memory session store is enough
- Replacing the default express-session
MemoryStorein an existing app that’s leaking memory from sessions that never expire - Prototypes and small internal tools where session data doesn’t need to survive a restart or be shared across processes
Under The Hood
Architecture
The package is a small factory-function wrapper, not a class exported directly: lib/memorystore.js exports a function that takes the caller’s express-session module and returns a MemoryStore class extending session.Store, which is how express-session’s official store contract expects the pattern (require('memorystore')(session)). Internally, each instance holds a single lru-cache instance (this.store) as its actual backing store, and every public method (get, set, destroy, touch, all, length, clear, ids) is a thin, direct translation from the express-session Store API to the corresponding lru-cache call, with a small runCallback/defer helper standing in for Node’s callback-based async convention (deferring via setImmediate rather than calling back synchronously, avoiding Zalgo). A module-level getTTL helper centralizes the ttl-resolution precedence (explicit option, function, cookie maxAge, one-day default) so it’s evaluated identically on every set/touch call.
Tech Stack
The only runtime dependencies are debug (namespaced memorystore logging, gated by the DEBUG env var) and lru-cache (pinned to the legacy ^4.0.3 API, which differs materially from lru-cache’s current major versions — the constructor is invoked as a function LRU(options), not new LRU(), and max accepts Infinity). There is no build step: it ships as plain CommonJS JavaScript with a hand-written index.d.ts for TypeScript consumers. Linting is enforced via standard and tests run under mocha (mocha --check-leaks --bail --no-exit), with Travis CI as the historical CI provider referenced in the README badge.
Code Quality
The single test file (test/store.js) instantiates the store directly against a stub { Store: class {} } in place of a real express-session module and exercises the documented option defaults, the max eviction boundary, destroy on both single and array session IDs, and the checkPeriod/prune interval behavior — a focused but not exhaustive suite, with no coverage tooling wired into CI. Error handling is explicit rather than swallowed: get, set, and touch all wrap serialization in try/catch and pass the error to the callback rather than throwing, matching the Node callback-error convention express-session expects. Naming and style are enforced by standard (zero-config ESLint preset), and the codebase is small enough (a single ~250-line core file) that its conventions are consistent throughout.
API Design
The public API mirrors express-session’s own Store contract almost exactly, so there’s essentially no new API surface to learn beyond new MemoryStore(options) — anyone who already knows express-session’s store interface can read this package’s README in a few minutes. The three added conveniences (checkPeriod, prune(), startInterval/stopInterval) are optional and orthogonal to the required interface, so the default configuration works with zero tuning. Documentation is a single, complete README section per option, and the TypeScript definitions give editor autocomplete for every constructor option without needing to read the source.