RateLimiter
Coordinates rate limits through shared persistent storage.
The RateLimiter service consumes tokens for string keys using fixed-window
counters or token-bucket state. It can protect external APIs, enforce quotas,
or throttle workers across fibers and processes that share the same store.
This module includes helpers that fail when a limit is exceeded, return the
delay needed before continuing, or wrap an effect so it waits automatically.
It also defines the store service and in-memory or Redis-backed store layers.
Accessors
makeWithRateLimiter
Accesses a function that applies rate limiting to an effect.
Signature
declare const makeWithRateLimiter: Effect.Effect<(options: { readonly algorithm?: "fixed-window" | "token-bucket"; readonly key: string; readonly limit: number; readonly onExceeded?: "delay" | "fail"; readonly tokens?: number; readonly window: Duration.Input;}) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E | RateLimiterError, R>, never, RateLimiter>Example
(Applying rate limits to effects)
import { Effect, Layer } from "effect"import { RateLimiter } from "effect/unstable/persistence"
const messages: Array<string> = []const program = Effect.gen(function*() { // Access the `withLimiter` function from the RateLimiter module const withLimiter = yield* RateLimiter.makeWithRateLimiter
// Apply a rate limiter to an effect yield* Effect.sync(() => messages.push("Making a request with rate limiting")).pipe( withLimiter({ key: "some-key", limit: 10, onExceeded: "delay", window: "5 seconds", algorithm: "fixed-window" }) )}).pipe( Effect.provide(RateLimiter.layer.pipe(Layer.provide(RateLimiter.layerStoreMemory))))
await Effect.runPromise(program)messages // => ["Making a request with rate limiting"]Sleeps when the rate limit is exceeded.
Signature
declare function sleep(self: RateLimiter): (options: { readonly algorithm?: "fixed-window" | "token-bucket"; readonly key: string; readonly limit: number; readonly tokens?: number; readonly window: Input;}) => Effect<ConsumeResult, RateLimiterError>declare function sleep(self: RateLimiter, options: { readonly algorithm?: "fixed-window" | "token-bucket"; readonly key: string; readonly limit: number; readonly tokens?: number; readonly window: Input;}): Effect<ConsumeResult, RateLimiterError>Example
(Sleeping until rate limit permits)
import { Effect, Layer } from "effect"import { RateLimiter } from "effect/unstable/persistence"
const program = Effect.gen(function*() { const limiter = yield* RateLimiter.RateLimiter const partiallyApplied = RateLimiter.sleep(limiter) const partial = yield* partiallyApplied({ key: "partial", limit: 10, window: "5 seconds", algorithm: "fixed-window" }) const direct = yield* RateLimiter.sleep(limiter, { key: "direct", limit: 10, window: "5 seconds", algorithm: "fixed-window" }) return [partial.remaining, direct.remaining]}).pipe( Effect.provide(RateLimiter.layer.pipe(Layer.provide(RateLimiter.layerStoreMemory))))
await Effect.runPromise(program) // => [9, 9]Constructors
Creates a RateLimiter from the current RateLimiterStore.
Details
The limiter supports fixed-window and token-bucket algorithms and either fails or returns a delay when a limit is exceeded.
Signature
declare const make: Effect.Effect<RateLimiter, never, RateLimiterStore>makeStoreRedis
Creates a Redis-backed RateLimiterStore using Lua scripts and the
configured key prefix.
Signature
declare const makeStoreRedis: (...args: [options?: { readonly prefix?: string;}]) => Effect<{ readonly adaptiveConsume: (options: AdaptiveConsumeOptions) => Effect<AdaptiveConsumeResult, RateLimiterError>; readonly adaptiveFeedback: (options: AdaptiveFeedbackOptions) => Effect<void, RateLimiterError>; readonly fixedWindow: (options: { readonly key: string; readonly limit: number | undefined; readonly refillRate: Duration; readonly tokens: number; }) => Effect<readonly [number, number], RateLimiterError>; readonly tokenBucket: (options: { readonly allowOverflow: boolean; readonly key: string; readonly limit: number; readonly refillRate: Duration; readonly tokens: number; }) => Effect<number, RateLimiterError>;}, never, Redis>Errors
RateLimiterError
Error raised by rate limiter operations, wrapping a concrete failure
reason.
Signature
declare class RateLimiterError extends { readonly _tag: "RateLimiterError"; readonly reason: RateLimitExceeded | RateLimitStoreError;} & YieldableError<this> { constructor(props: { readonly reason: RateLimiterErrorReason; }); readonly "~@effect/experimental/RateLimiter/RateLimiterError": "~@effect/experimental/RateLimiter/RateLimiterError"; message: string;}RateLimiterErrorReason
Schema for all reasons that can be carried by RateLimiterError.
Signature
declare const RateLimiterErrorReason: Union<[typeof RateLimitExceeded, typeof RateLimitStoreError]>RateLimiterErrorReason type
Union of reasons carried by RateLimiterError.
Signature
type RateLimiterErrorReason = RateLimitExceeded | RateLimitStoreErrorRateLimitExceeded
Error reason for a rate-limit check that exceeded the configured limit.
Details
Includes the affected key, limit, remaining token count, and retry delay.
Signature
declare class RateLimitExceeded extends { readonly _tag: "RateLimitExceeded"; readonly key: string; readonly limit: number; readonly remaining: number; readonly retryAfter: Duration;} & YieldableError<this> { constructor(...args: [props: { readonly _tag?: "RateLimitExceeded"; readonly key: string; readonly limit: number; readonly remaining: number; readonly retryAfter: Duration; }, options?: MakeOptions]); message: string;}RateLimitStoreError
Error reason for failures in the backing RateLimiterStore.
Signature
declare class RateLimitStoreError extends { readonly _tag: "RateLimitStoreError"; readonly cause?: unknown; readonly message: string;} & YieldableError<this> { constructor(...args: [props: { readonly _tag?: "RateLimitStoreError"; readonly cause?: unknown; readonly message: string; }, options?: MakeOptions]);}Layers
Provides RateLimiter using the current RateLimiterStore.
Signature
declare const layer: Layer.Layer<RateLimiter, never, RateLimiterStore>layerStoreMemory
Provides a process-local in-memory RateLimiterStore.
Signature
declare const layerStoreMemory: Layer.Layer<RateLimiterStore>layerStoreRedis
Provides a Redis-backed RateLimiterStore using makeStoreRedis.
Signature
declare const layerStoreRedis: (options?: { readonly prefix?: string;}) => Layer.Layer<RateLimiterStore, never, Redis.Redis>layerStoreRedisConfig
Provides a Redis-backed RateLimiterStore from wrapped configuration
options.
Signature
declare function layerStoreRedisConfig(options: { readonly prefix?: Config<string | undefined>;} | Config<{ readonly prefix?: string;}>): Layer<RateLimiterStore, ConfigError, Redis>Models
AdaptiveConsumeResult interface
Metadata returned after consuming tokens from the adaptive rate limiter store.
Signature
interface AdaptiveConsumeResult { readonly delay: Duration; readonly epoch: number; readonly phase: AdaptivePhase;}AdaptivePhase type
Phase of adaptive rate limiting driven by server feedback.
Signature
type AdaptivePhase = "inactive" | "cooldown" | "learning" | "learned"ConsumeResult interface
Metadata returned after consuming tokens from a rate limiter.
Signature
interface ConsumeResult { readonly delay: Duration; readonly limit: number; readonly remaining: number; readonly resetAfter: Duration;}RateLimiter interface
Service for consuming rate-limit tokens for a key using fixed-window or token-bucket algorithms.
Signature
interface RateLimiter { readonly "~effect/persistence/RateLimiter": "~effect/persistence/RateLimiter"; readonly adaptiveConsume: (options: AdaptiveConsumeOptions) => Effect<AdaptiveConsumeResult, RateLimiterError>; readonly adaptiveFeedback: (options: AdaptiveFeedbackOptions) => Effect<void, RateLimiterError>; readonly consume: (options: { readonly algorithm?: "fixed-window" | "token-bucket"; readonly key: string; readonly limit: number; readonly onExceeded?: "delay" | "fail"; readonly tokens?: number; readonly window: Input; }) => Effect<ConsumeResult, RateLimiterError>;}Options
AdaptiveConsumeOptions interface
Options for consuming tokens from the adaptive rate limiter store.
Signature
interface AdaptiveConsumeOptions { readonly fallbackLimit: number; readonly fallbackWindow: Duration; readonly key: string; readonly tokens: number;}AdaptiveFeedbackOptions interface
Options for reporting response feedback to the adaptive rate limiter store.
Signature
interface AdaptiveFeedbackOptions { readonly epoch: number; readonly key: string; readonly retryAfter: Duration | undefined; readonly status: number; readonly tokens: number;}Services
RateLimiter
Service tag for persistent token-consumption services.
When to use
Use to access or provide rate-limit checks backed by fixed-window counters or token-bucket state.
Signature
declare const RateLimiter: Service<RateLimiter, RateLimiter>RateLimiterStore
Defines the low-level backing store for rate-limit state.
When to use
Use to provide the shared counter storage and adaptive feedback state used by persistent rate-limit checks.
Signature
declare class RateLimiterStore extends Shape<"effect/persistence/RateLimiter/RateLimiterStore", { readonly adaptiveConsume: (options: AdaptiveConsumeOptions) => Effect<AdaptiveConsumeResult, RateLimiterError>; readonly adaptiveFeedback: (options: AdaptiveFeedbackOptions) => Effect<void, RateLimiterError>; readonly fixedWindow: (options: { readonly key: string; readonly limit: number | undefined; readonly refillRate: Duration; readonly tokens: number; }) => Effect<readonly [number, number], RateLimiterError>; readonly tokenBucket: (options: { readonly allowOverflow: boolean; readonly key: string; readonly limit: number; readonly refillRate: Duration; readonly tokens: number; }) => Effect<number, RateLimiterError>;}, this> { constructor(_: never);}Type IDs
ErrorTypeId
Runtime type identifier for RateLimiterError.
Signature
declare const ErrorTypeId: ErrorTypeIdErrorTypeId type
Type-level identifier used to brand RateLimiterError values.
Signature
type ErrorTypeId = "~@effect/experimental/RateLimiter/RateLimiterError"Runtime type identifier for RateLimiter values.
Signature
declare const TypeId: TypeIdType-level identifier used to brand RateLimiter values.
Signature
type TypeId = "~effect/persistence/RateLimiter"