Skip to content
Effect Days 2026 Get your ticket

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.

25 exports Added in v4.0.0 Source

Accessors

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"]

sleep

Added in v4.0.0 Source

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

make

Added in v4.0.0 Source

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>

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

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;
}

Schema for all reasons that can be carried by RateLimiterError.

Signature

declare const RateLimiterErrorReason: Union<[typeof RateLimitExceeded, typeof RateLimitStoreError]>

Union of reasons carried by RateLimiterError.

Signature

type RateLimiterErrorReason = RateLimitExceeded | RateLimitStoreError

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;
}

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

layer

Added in v4.0.0 Source

Provides RateLimiter using the current RateLimiterStore.

Signature

declare const layer: Layer.Layer<RateLimiter, never, RateLimiterStore>

Provides a process-local in-memory RateLimiterStore.

Signature

declare const layerStoreMemory: Layer.Layer<RateLimiterStore>

Provides a Redis-backed RateLimiterStore using makeStoreRedis.

Signature

declare const layerStoreRedis: (options?: {
readonly prefix?: string;
}) => Layer.Layer<RateLimiterStore, never, Redis.Redis>

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

Added in v4.0.0 Source

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

Added in v4.0.0 Source

Phase of adaptive rate limiting driven by server feedback.

Signature

type AdaptivePhase = "inactive" | "cooldown" | "learning" | "learned"

ConsumeResult interface

Added in v4.0.0 Source

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

Added in v4.0.0 Source

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

Added in v4.0.0 Source

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

Added in v4.0.0 Source

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

Added in v4.0.0 Source

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>

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

Added in v4.0.0 Source

Runtime type identifier for RateLimiterError.

Signature

declare const ErrorTypeId: ErrorTypeId

ErrorTypeId type

Added in v4.0.0 Source

Type-level identifier used to brand RateLimiterError values.

Signature

type ErrorTypeId = "~@effect/experimental/RateLimiter/RateLimiterError"

TypeId

Added in v4.0.0 Source

Runtime type identifier for RateLimiter values.

Signature

declare const TypeId: TypeId

TypeId type

Added in v4.0.0 Source

Type-level identifier used to brand RateLimiter values.

Signature

type TypeId = "~effect/persistence/RateLimiter"