Ratelock

Engines

Redis Engine

Distributed rate limiting powered by Redis and atomic Lua scripts.

The Redis engine executes atomic Lua scripts for distributed rate limiting. Each strategy picks the Redis data structure that fits its algorithm:

  • Fixed Window uses GET/SET/INCR counters with millisecond TTLs.
  • Sliding Window uses sorted sets (ZADD, ZCARD, ZRANGE) to track per-request timestamps.
  • Token Bucket uses hashes (HMGET/HMSET) to store the token count and last-refill time.
  • Individual Fixed Window uses two keys per identifier (start + count) with GET/SET/INCR.

The engine supports redis (node-redis), ioredis, and Bun's native client (Bun >= 1.4), and runs on every supported runtime.

Installation

npm install @ratelock/redis redis
# or with ioredis
npm install @ratelock/redis ioredis

Quick Start

With a Connection URL

import { fixedWindow } from '@ratelock/redis'

const limiter = await fixedWindow({
    url: 'redis://localhost:6379',
    limit: 100,
    windowMs: 60_000,
})

With an Existing Client (node-redis)

import { createClient } from 'redis'
import { fixedWindow } from '@ratelock/redis'

const redisClient = createClient({ url: 'redis://localhost:6379' })
await redisClient.connect()

const limiter = await fixedWindow({
    client: redisClient,
    limit: 100,
    windowMs: 60_000,
    prefix: 'my-app', // Optional key prefix
})

With ioredis

import IORedis from 'ioredis'
import { fixedWindow } from '@ratelock/redis'

const limiter = await fixedWindow({
    client: new IORedis('redis://localhost:6379'),
    limit: 100,
    windowMs: 60_000,
})

With Bun's native client

Zero dependency — pass a client instance or set driver: 'bun':

import { RedisClient } from 'bun'
import { fixedWindow } from '@ratelock/redis'

const limiter = await fixedWindow({
    client: new RedisClient('redis://localhost:6379'),
    limit: 100,
    windowMs: 60_000,
})

Configuration Options

All limiters in the Redis engine accept these shared base options:

Prop

Type

Built-in Resilience Policies

All limiters accept optional resilience configurations at creation time:

const limiter = await fixedWindow({
    url: 'redis://localhost:6379',
    limit: 100,
    windowMs: 60_000,
    cache: { maxSize: 1000, ttlMs: 30_000 }, // Cache denied results in memory
    retry: { maxAttempts: 3 }, // Retry transient Redis failures
    circuitBreaker: { failureThreshold: 5, recoveryTimeoutMs: 30_000 },
    fallback: 'allow', // Fail-open if Redis is down
})
OptionTypeDescription
cacheCacheConfigCache denied results in memory to reduce Redis load
retryRetryConfigRetry transient failures with exponential backoff
circuitBreakerCircuitBreakerConfigStop calling Redis after consecutive failures
fallback'throw' | 'allow' | 'deny'Behavior when the limiter throws

All Strategies

import { fixedWindow, slidingWindow, tokenBucket, individualFixedWindow } from '@ratelock/redis'

Standalone Policies (Advanced)

For advanced use cases (conditional policies, dynamic composition), import standalone wrappers directly:

import { withCache, withRetry } from '@ratelock/redis'

const limiter = await fixedWindow({ url: 'redis://...', limit: 100, windowMs: 60_000 })
const cached = withCache(limiter, { maxSize: 500, ttlMs: 10_000 })

See Resilience Policies for full documentation and when to use standalone vs built-in.

API Reference

The factory functions accept these configuration types:

FixedWindowLimiterConfig

Prop

Type

Valkey Compatibility

RateLock works with Valkey (the Redis-compatible fork). Use @ratelock/redis with standard ioredis or node-redis clients.

Note

Use standard ioredis or node-redis clients. Valkey-specific clients are not tested.

When to Use

  • Multi-server or serverless deployments
  • When you need consistent rate limits across processes
  • High-traffic applications requiring Redis-level performance
  • When atomicity matters (no race conditions between checks)

Cleanup

await limiter.destroy() // Closes the Redis connection (if created internally)

If you provide your own client, destroy() does not close it - you manage the client lifecycle yourself.

How is this guide?

Last updated on

On this page