Most production APIs need to enforce several independent constraints at once — a per-IP limit, a per-user quota, and a per-route ceiling — and they must be atomic: you cannot allow a request against the per-IP dimension and then separately deny it on the per-user dimension, because state would already be consumed.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.
multiRateLimit evaluates all configured dimensions together in one atomic step, committing state only when the combined decision is “allow.”
On a Redis store, every dimension is evaluated in a single Lua round trip — regardless of how many dimensions you configure. On an in-process synchronous store, all dimensions are read, the decision is computed, and state is committed in one uninterrupted synchronous turn with no partial-consume risk.
multiRateLimit()
MultiRateLimitOptions
A composite built with
all() or any(). Specifies the dimensions and combine mode.The backing store. Defaults to a new
MemoryStore. For Redis, every dimension is fused into a single atomic Lua script.Injected time source. Defaults to the system clock.
Key namespace prepended to every dimension’s store key.
Dimension and Dimensions
Each dimension specifies how to derive its key from the request context, which algorithm to enforce, and an optional per-dimension cost weight:
Dimensions record) become part of the Redis key namespace: {prefix}:{name}:{raw-key}.
all() — Every Dimension Must Pass
all(dimensions) builds a MultiStrategy where a request is allowed only if every dimension allows. If any dimension denies, no state is consumed for any dimension — zero partial-consume.
On allow, the combined Decision reflects the binding dimension: the one with the lowest remaining (the tightest headroom). On deny, it reflects the dimension with the largest retryAfterMs (the longest you must wait before all constraints are satisfied simultaneously).
any() — At Least One Dimension Must Pass
any(dimensions) allows a request if at least one dimension allows. State is consumed only for the dimensions that individually allowed — denied dimensions are not decremented.
On allow, the combined Decision reflects the dimension with the most remaining. On deny (all dimensions failed), it reflects the dimension with the smallest retryAfterMs (soonest recovery).
combineDecisions
The decision-combination logic is not hidden inside multiRateLimit — it is the same exported combineDecisions primitive used by unifiedAdmission. You can use it directly when combining independently-checked decisions in application code:
MultiLimiter Interface
checkSync requires a synchronous store (e.g. MemoryStore). On an async store it throws. reset deletes the keys for all dimensions for the given context.
Full Example
Performance: Single Round Trip
When using a Redis store,multiRateLimit fuses all dimensions into a single Lua EVAL call. The script evaluates GCRA, token-bucket, and fixed-window dimensions in one pass, applies the combine rule in Lua, and commits state (all-or-none per mode) atomically in that same script. You pay one round trip regardless of the number of dimensions configured.
On a synchronous store, all dimensions are read in a single uninterrupted JavaScript turn, the decision is computed, and state is committed — also with no interleaving risk.
The Lua fused path supports
gcra, tokenBucket, and fixedWindow dimensions. Configuring a dimension with a different strategy on an async (Redis) store will throw at the first check() call. On a sync store (MemoryStore), any strategy is supported.FAQ: What happens on a partial failure — if one dimension's key doesn't exist in Redis?
FAQ: What happens on a partial failure — if one dimension's key doesn't exist in Redis?
The Lua script handles absent state by treating it as the initial state for that strategy (e.g. zero usage for a fixed-window counter). The all-or-none commit means either all allowing dimensions are updated atomically, or none are — you cannot observe a state where two dimensions were updated but a third was not.
FAQ: Can I mix Redis and in-process dimensions?
FAQ: Can I mix Redis and in-process dimensions?
No.
multiRateLimit uses a single store for all dimensions. If you need axes from different stores, compose them with unifiedAdmission (rate + concurrency + cost axes each with their own store) or chain separate limiters manually. multiRateLimit is designed for the case where all dimensions share the same store and you want them fused into one atomic round trip.