npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@ikrbasak/rate-limiter

v0.2.1

Published

Lightweight, pluggable, and production-ready rate limiter for Node.js. Supports fine-grained control over rate limiting strategies (fixed window, sliding window, token bucket).

Readme

Rate Limiter (@ikrbasak/rate-limiter)

A flexible, Redis-backed rate limiter for Node.js applications supporting multiple algorithms: Fixed Window, Sliding Window, and Token Bucket.

Features

  • 🚀 Multiple Algorithms: Fixed Window, Sliding Window, and Token Bucket
  • 🔄 Redis-backed: Distributed rate limiting across multiple instances
  • 📝 TypeScript Support: Full type safety with comprehensive JSDoc documentation
  • High Performance: Optimized Redis operations with pipelining
  • 🎯 Dynamic Configuration: Support for dynamic keys and limits using sync/async functions
  • 🛡️ Production Ready: Battle-tested algorithms with proper error handling

Installation

npm install @ikrbasak/rate-limiter ioredis
yarn add @ikrbasak/rate-limiter ioredis
pnpm add @ikrbasak/rate-limiter ioredis

Quick Start

import Redis from 'ioredis';
import RateLimiter from '@ikrbasak/rate-limiter';

// Initialize Redis connection
const redis = new Redis('redis://localhost:6379');

// Create rate limiter instance
const rateLimiter = new RateLimiter(redis, {
  prefix: 'api', // Optional: custom Redis key prefix, defaults to 'rl'
});

// Create a rate limiter
const limiter = rateLimiter.create({
  algo: 'fixed_window',
  key: 'user:123',
  window: 60000, // 1 minute in milliseconds
  limit: 100, // 100 requests per minute
});

// Check rate limit
const result = await limiter.evaluate();

if (result.allowed) {
  // Process the request
  console.log(`Request allowed. ${result.remaining} requests remaining.`);
} else {
  // Rate limit exceeded
  console.log(`Rate limit exceeded. Retry after ${result.retryAfter} seconds.`);
}

Algorithms

1. Fixed Window

Divides time into fixed intervals and counts requests within each interval.

const limiter = rateLimiter.create({
  algo: 'fixed_window',
  key: 'api:user:123',
  window: 60000, // 1 minute window
  limit: 100, // 100 requests per window
});

Use cases:

  • Simple API rate limiting
  • Resource quotas
  • Basic request throttling

Pros: Simple, memory efficient

Cons: Potential burst at window boundaries

2. Sliding Window

Maintains a log of request timestamps and counts requests within a sliding time window.

const limiter = rateLimiter.create({
  algo: 'sliding_window',
  key: 'api:user:123',
  window: 60000, // 1 minute sliding window
  limit: 100, // 100 requests per minute
});

Use cases:

  • More accurate rate limiting
  • Preventing burst attacks
  • Fair usage enforcement

Pros: Accurate, smooth rate limiting

Cons: Higher memory usage

3. Token Bucket

Maintains a bucket of tokens that are consumed by requests and refilled at a constant rate.

const limiter = rateLimiter.create({
  algo: 'token_bucket',
  key: 'api:user:123',
  window: 3600000, // 1 hour token bucket lifetime
  limit: 1000, // Maximum 1000 tokens
  refill: 10, // 10 tokens per second
});

Use cases:

  • Allowing burst traffic
  • Credit-based systems
  • Flexible rate limiting

Pros: Allows bursts, flexible

Cons: More complex to understand

Configuration Options

Common Options

type CommonRateLimiterOptions = {
  key: string | ValueGenerator<string>; // Static string or function that returns string
  window: number; // Time window in milliseconds (positive integer)
  limit: number | ValueGenerator<number>; // Static number or function that returns number
};

Algorithm-Specific Options

Fixed Window & Sliding Window

{
  algo: 'fixed_window' | 'sliding_window',
  key: string | (() => string) | (() => Promise<string>),
  limit: number | (() => number) | (() => Promise<number>)
}

Token Bucket

{
  algo: 'token_bucket',
  key: string | (() => string) | (() => Promise<string>),
  limit: number | (() => number) | (() => Promise<number>), // Maximum tokens
  refill: number // Refill rate per second (positive number)
}

Advanced Usage

Dynamic Keys

Use functions for dynamic rate limiting:

// Synchronous key generation
const limiter = rateLimiter.create({
  algo: 'sliding_window',
  key: () => `user:${getCurrentUserId()}:${getClientIP()}`,
  window: 60000,
  limit: 50,
});

// Asynchronous key generation
const asyncLimiter = rateLimiter.create({
  algo: 'token_bucket',
  key: async (id: number) => {
    const userId = await getUserId(id);
    const tier = await getUserTier(userId);
    return `${tier}:${userId}`;
  },
  window: 3600000,
  limit: 1000,
  refill: 1,
});

Dynamic Limits

Adjust limits based on user tiers, time of day, or other factors:

// Synchronous limit generation
const limiter = rateLimiter.create({
  algo: 'fixed_window',
  key: 'api:user:123',
  window: 60000,
  limit: () => {
    const hour = new Date().getHours();
    return hour >= 9 && hour <= 17 ? 1000 : 100; // Higher limits during business hours
  },
});

// Asynchronous limit generation
const premiumLimiter = rateLimiter.create({
  algo: 'sliding_window',
  key: 'api:user:123',
  window: 60000,
  limit: async () => {
    const user = await getUserById(123);
    return user.tier === 'premium' ? 1000 : 100;
  },
});

Multiple Rate Limiters

Combine different algorithms for comprehensive protection:

// Burst protection (short-term)
const burstLimiter = rateLimiter.create({
  algo: 'fixed_window',
  key: 'api:user:123',
  window: 1000, // 1 second
  limit: 10,
});

// Sustained usage (long-term)
const sustainedLimiter = rateLimiter.create({
  algo: 'sliding_window',
  key: 'api:user:123',
  window: 3600000, // 1 hour
  limit: 1000,
});

// Check both limits
const [burstResult, sustainedResult] = await Promise.all([
  burstLimiter.evaluate(),
  sustainedLimiter.evaluate(),
]);

const allowed = burstResult.allowed && sustainedResult.allowed;

Response Format

The evaluate() method returns a RateLimiterEvaluationResult:

{
  limit: number; // Applied limit (positive integer)
  allowed: boolean; // Whether request is allowed
  remaining: number; // Requests remaining (non-negative integer)
  retryAfter: number; // Seconds to wait before retry (0 if allowed)
}

Best Practices

1. Choose the Right Algorithm

  • Fixed Window: Simple APIs, basic protection, memory efficient
  • Sliding Window: Accurate limiting, prevent bursts, fair usage
  • Token Bucket: Allow legitimate bursts, credit systems, flexible limits

2. Key Design

// Good: Specific and meaningful keys
key: () => `api:${endpoint}:user:${userId}`;
key: () => `download:${fileId}:ip:${clientIP}`;
key: async (id: number) => `tier:${await getUserTier(number)}:${userId}`;

// Avoid: Too generic or static when dynamic is needed
key: 'user';
key: 'api';

3. Window Sizing

// Multiple time windows for different scenarios
const shortTerm = { window: 1000, limit: 5 }; // Burst protection
const mediumTerm = { window: 60000, limit: 100 }; // Per-minute limits
const longTerm = { window: 3600000, limit: 1000 }; // Hourly quotas

Redis Configuration

For optimal performance, configure Redis with:

# Redis configuration for rate limiting
maxmemory-policy allkeys-lru
tcp-keepalive 60
timeout 300

Performance Considerations

  • Connection Pooling: Use Redis connection pooling for high-traffic applications
  • Key Expiration: All keys are automatically set to expire to prevent memory leaks
  • Pipeline Operations: The library uses Redis transactions for atomic operations
  • Memory Usage: Sliding window uses more memory than fixed window due to timestamp storage
  • Dynamic Function Caching: Cache results of expensive async operations when possible

TypeScript Support

The library is written in TypeScript and provides full type safety:

import RateLimiter, {
  RateLimiterOptions,
  RateLimiterEvaluationResult,
  ValueGenerator,
  FixedWindowRateLimiterOptions,
  SlidingWindowRateLimiterOptions,
  TokenBucketRateLimiterOptions,
} from '@ikrbasak/rate-limiter';

// Type-safe configuration
const options: FixedWindowRateLimiterOptions = {
  algo: 'fixed_window',
  key: 'user:123',
  window: 60000,
  limit: 100,
};

// Type-safe result handling
const result: RateLimiterEvaluationResult = await limiter.evaluate();

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feat/amazing-feature)
  3. Commit your changes (git commit -m 'feat: some amazing feature')
  4. Push to the branch (git push origin feat/amazing-feature)
  5. Open a Pull Request

License

MIT License. See LICENSE file for details.

Support


Keywords: rate limiting, Redis, TypeScript, Node.js, API, throttling, token bucket, sliding window, fixed window, dynamic configuration