Documentation Index
Fetch the complete documentation index at: https://mintlify.com/AmeyaBorkar/throttlekit/llms.txt
Use this file to discover all available pages before exploring further.
MemoryStore is the default backend that ships inside ThrottleKit’s core package — no installation step, no peer dependencies, no network. All state lives in a plain JavaScript Map, and because Node.js is single-threaded, a synchronous read-modify-write cannot interleave: applySync needs no locks and pays zero coordination overhead. The async apply simply resolves the same result, so every algorithm works identically on both the sync and async code paths.
How it works
Timing-wheel expiry. Keys are bucketed intowheelSize hash-slots by their expiry tick. Each call to applySync advances the wheel to the current time, expiring only the slots that have come due — O(due keys), not O(all keys). A per-entry exp field on each map entry provides inline lazy expiry on the hot path without a second map lookup.
CLOCK eviction. When maxKeys is set, cardinality is bounded by a second-chance ring. Each key access sets a reference bit; a sweeping hand clears bits and evicts the first key whose bit is already clear. This is O(1) amortized and reorder-free — it defends against adversarial floods of unique keys (e.g. spoofed IPs) without the per-read linked-list pointer updates that a true LRU would require.
Background sweep. A setInterval timer (default every 5 000 ms) advances the wheel even when traffic is idle, reclaiming memory from keys that stopped receiving requests. The timer is unref’d so it never prevents a Node process from exiting. Set sweepIntervalMs: 0 to disable it entirely — the right choice on edge runtimes that discourage background timers.
Installation
MemoryStore is part of the throttlekit core package. No extra packages needed.
Quick example
Deterministic testing with ManualClock
Inject a ManualClock to drive time forward deterministically in unit tests — no setTimeout, no sleep.
Options
Injected time source. Defaults to the system clock (
Date.now()). Pass a
ManualClock to drive expiry deterministically in tests.Maximum number of distinct live keys before CLOCK (second-chance) eviction
kicks in. Unbounded when omitted. Set this on any public endpoint so a
flood of unique keys cannot grow the map without limit.
Background sweep interval in milliseconds. The timer advances the timing
wheel so idle keys are reclaimed even without incoming traffic. Set
0 to
disable the timer entirely — cleanup then becomes purely access-driven, which
is the right choice on edge runtimes.Timing-wheel tick resolution in milliseconds. This is the cleanup granularity
(i.e. how precisely expired keys are reclaimed), not the decision precision —
every decision is exact regardless of tick size.
Number of slots in the timing wheel. Together with
tickMs, this sets the
span before TTLs “lap”: tickMs × wheelSize milliseconds. The default covers
~8.5 minutes at 1 s resolution, which suits most window sizes.applySync / checkSync
MemoryStore is the only built-in store that exposes a fully synchronous code path. applySync performs the read-modify-write in one JavaScript turn — no await, no microtask queue entry. Use limiter.checkSync(key) to take advantage of it in latency-critical hot paths such as tight request loops or middleware stacks that cannot tolerate even a single task boundary.
checkSync throws if the limiter’s store does not implement applySync.
All distributed stores (Redis, Postgres, DynamoDB, edge) are async-only —
always use await limiter.check(key) with those backends.When to use
MemoryStore is the right choice when:
- You are running a single process (or each process enforces its own independent limit).
- You are writing unit tests and want deterministic, clock-controlled behavior.
- You are prototyping or running local development and do not want to spin up Redis or Postgres.
- You want the absolute lowest latency — no network hop, no serialization, no lock contention.
MemoryStore with a distributed backend via twoTier: the memory tier absorbs the hot path and the distributed tier enforces the global cap.