
Redis storage for NestJS Throttler with distributed rate limiting
Built on node-redis • Drop-in replacement • Distributed rate limiting
- 🎯 Why This Package?
- ✨ Features
- 📦 Installation
- 🚀 Quick Start
- 🔧 Configuration
- 📚 API Reference
- 🔄 Migration Guide
- 🤝 Contributing
- 📄 License
The @nestjs-redis/throttler-storage
package provides Redis-based storage for NestJS Throttler, enabling distributed rate limiting across multiple application instances. Key benefits:
- Distributed Rate Limiting: Share rate limits across multiple app instances and servers
- Production Tested: Battle-tested in high-traffic production environments
- Drop-in Replacement: Seamlessly replaces the default in-memory throttler storage
-
Future-Proof: Built on the modern
node-redis
client for long-term reliability
- 🚀 Production Ready — Tested and used in high-traffic production environments
- 🔄 Drop-in Replacement — Works seamlessly with existing NestJS Throttler setup
- 🌐 Distributed Rate Limiting — Share rate limits across multiple application instances
- 🏗️ Multi-Redis Support — Compatible with Redis Client, Cluster, and Sentinel
- 🎯 Clean Factory API — Explicit static methods for clear initialization
- ⚡ Lifecycle Management — Automatic connection handling and cleanup
- 🛡️ Type Safe — Full TypeScript support with comprehensive type definitions
# Install the package and dependencies
npm install @nestjs-redis/throttler-storage redis
# Or with yarn
yarn add @nestjs-redis/throttler-storage redis
# Or with pnpm
pnpm add @nestjs-redis/throttler-storage redis
Dependency | Version | Required |
---|---|---|
@nestjs/common |
^9.0.0 || ^10.0.0 || ^11.0.0 | ✅ Peer |
@nestjs/throttler |
^6.4.0 | ✅ Peer |
redis |
^5.0.0 | ✅ Peer |
Node.js |
18+ | ✅ Runtime |
Single connection:
import { Module } from '@nestjs/common';
import { ThrottlerModule, seconds } from '@nestjs/throttler';
import { RedisModule, RedisToken } from '@nestjs-redis/client';
import { RedisThrottlerStorage } from '@nestjs-redis/throttler-storage';
@Module({
imports: [
RedisModule.forRoot({
url: 'redis://localhost:6379',
}),
ThrottlerModule.forRootAsync({
inject: [RedisToken()],
useFactory: (redis) => ({
throttlers: [{ limit: 5, ttl: seconds(60) }],
storage: RedisThrottlerStorage.from(redis),
}),
}),
],
})
export class AppModule {}
Named connection (multi-connection):
import { Module } from '@nestjs/common';
import { ThrottlerModule, seconds } from '@nestjs/throttler';
import { RedisModule, RedisToken } from '@nestjs-redis/client';
import { RedisThrottlerStorage } from '@nestjs-redis/throttler-storage';
@Module({
imports: [
RedisModule.forRoot({
connections: [
{
connection: 'cache',
type: 'client',
options: { url: 'redis://localhost:6379' },
},
{
connection: 'throttling',
type: 'client',
options: { url: 'redis://localhost:6380' },
},
],
}),
ThrottlerModule.forRootAsync({
inject: [RedisToken('throttling')],
useFactory: (redis) => ({
throttlers: [{ limit: 5, ttl: seconds(60) }],
storage: RedisThrottlerStorage.from(redis),
}),
}),
],
})
export class AppModule {}
import { Module } from '@nestjs/common';
import { ThrottlerModule, seconds } from '@nestjs/throttler';
import { RedisThrottlerStorage } from '@nestjs-redis/throttler-storage';
import { createClient, createCluster, createSentinel } from 'redis';
@Module({
imports: [
ThrottlerModule.forRoot({
throttlers: [{ limit: 5, ttl: seconds(60) }],
// Generic method for existing Redis client/cluster/sentinel
storage: RedisThrottlerStorage.from(
createClient({ url: 'redis://localhost:6379' }),
),
// Redis client from options
storage: RedisThrottlerStorage.fromClientOptions({
url: 'redis://localhost:6379',
}),
// Redis cluster from options
storage: RedisThrottlerStorage.fromClusterOptions({
rootNodes: [{ url: 'redis://localhost:7000' }],
}),
// Redis sentinel from options
storage: RedisThrottlerStorage.fromSentinelOptions({
sentinels: [{ host: 'localhost', port: 26379 }],
name: 'mymaster',
}),
}),
],
})
export class AppModule {}
@Module({
imports: [
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
throttlers: [{ limit: 10, ttl: seconds(60) }],
storage: RedisThrottlerStorage.fromClientOptions({
url: configService.get('REDIS_URL'),
password: configService.get('REDIS_PASSWORD'),
}),
}),
}),
],
})
export class AppModule {}
Method | Description | Lifecycle Management |
---|---|---|
from(client) |
Unified method for existing Redis client/cluster/sentinel with optional lifecycle management | ❌ Not managed |
fromClientOptions(options) |
Creates Redis client from options | ✅ Managed |
fromClusterOptions(options) |
Creates Redis cluster from options | ✅ Managed |
fromSentinelOptions(options) |
Creates Redis sentinel from options | ✅ Managed |
Lifecycle Management:
- ✅ Managed: The storage instance will automatically connect/disconnect the Redis instance during application bootstrap/shutdown.
- ❌ Not managed: You are responsible for managing the Redis connection lifecycle.
- 🔧 Configurable: Lifecycle management can be controlled via the optional
manageClientLifecycle
parameter (defaults tofalse
).
The RedisThrottlerStorage
implements the NestJS ThrottlerStorage
interface:
interface ThrottlerStorage {
increment(
key: string,
ttl: number,
limit: number,
blockDuration: number,
): Promise<ThrottlerStorageRecord>;
}
interface ThrottlerStorageRecord {
totalHits: number;
timeToExpire: number;
isBlocked: boolean;
}
// Before (in-memory)
@Module({
imports: [
ThrottlerModule.forRoot({
throttlers: [{ limit: 10, ttl: seconds(60) }],
// No storage specified - uses in-memory by default
}),
],
})
export class AppModule {}
// After (Redis storage)
@Module({
imports: [
ThrottlerModule.forRoot({
throttlers: [{ limit: 10, ttl: seconds(60) }],
storage: RedisThrottlerStorage.fromClientOptions({
url: 'redis://localhost:6379',
}),
}),
],
})
export class AppModule {}
Contributions are welcome! Please see the main repository for contributing guidelines.
MIT © CSenshi