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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@samahuja642/rate-limiter

v1.0.0

Published

A flexible, customizable rate limiting package for Node.js with multiple algorithms and storage backends

Readme

@samahuja642/rate-limiter

A flexible, production-ready rate limiting package for Node.js with multiple algorithms, storage backends, and framework integrations.

License: MIT

Features

  • 🚀 Multiple Algorithms: Fixed Window, Leaky Bucket
  • 💾 Flexible Storage: In-memory (default) and Redis support
  • 🔌 Framework Integration: Express and generic middleware
  • 📘 TypeScript: Full type definitions included
  • High Performance: Minimal overhead, optimized for production
  • 🛡️ Battle-tested: Comprehensive test coverage
  • 🎯 Customizable: Extensive configuration options

Installation

npm install @samahuja642/rate-limiter

For Redis support:

npm install @samahuja642/rate-limiter redis
# or
npm install @samahuja642/rate-limiter ioredis

Quick Start

Express with Fixed Window (In-Memory)

const express = require('express');
const { FixedWindow, MemoryStorage, createExpressMiddleware } = require('@samahuja642/rate-limiter');

const app = express();

// Create storage and rate limiter
const storage = new MemoryStorage();
const limiter = new FixedWindow(storage, {
  maxRequests: 100,     // Max requests
  windowMs: 60000       // Per minute
});

// Apply to all routes
app.use(createExpressMiddleware({ limiter }));

app.get('/api/data', (req, res) => {
  res.json({ message: 'Success!' });
});

app.listen(3000);

Express with Redis (Distributed)

const express = require('express');
const redis = require('redis');
const { FixedWindow, RedisStorage, createExpressMiddleware } = require('@samahuja642/rate-limiter');

const app = express();

// Create Redis client and storage
const redisClient = redis.createClient({ url: 'redis://localhost:6379' });
await redisClient.connect();

const storage = new RedisStorage(redisClient);
const limiter = new FixedWindow(storage, {
  maxRequests: 100,
  windowMs: 60000 // 100 requests per minute
});

app.use(createExpressMiddleware({ limiter }));

app.listen(3000);

Algorithms

Comparison Table

| Algorithm | Bursts Allowed | Memory Usage | Accuracy | Best For | |-----------|---------------|--------------|----------|----------| | Fixed Window | ⚠️ At boundaries | Very Low | Fair | Simple rate limiting | | Leaky Bucket | ❌ No | Low | Good | Traffic shaping |

Fixed Window

Simple counter that resets at fixed intervals.

const limiter = new FixedWindow(storage, {
  maxRequests: 100,
  windowMs: 60000 // 100 requests per minute
});

Use case: Simple rate limiting, low-memory environments

Leaky Bucket

Smooths traffic to a constant output rate.

const limiter = new LeakyBucket(storage, {
  capacity: 100,
  leakRate: 10 // 10 requests per second
});

Use case: Upstream rate limiting, traffic shaping

Storage Backends

In-Memory Storage

Default storage for single-instance applications.

const { MemoryStorage } = require('@samahuja642/rate-limiter');

const storage = new MemoryStorage(300000); // Cleanup every 5 minutes

Pros: Fast, no external dependencies
Cons: Not suitable for multi-instance deployments

Redis Storage

For distributed applications across multiple instances.

const redis = require('redis');
const { RedisStorage } = require('@samahuja642/rate-limiter');

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

const storage = new RedisStorage(client, 'myapp:ratelimit:');

Pros: Distributed, persistent, scalable
Cons: Requires Redis server

Custom Storage

Implement the Storage interface for custom backends:

interface Storage {
  get<T>(key: string): Promise<T | null>;
  set<T>(key: string, value: T, ttl?: number): Promise<void>;
  increment(key: string, amount?: number): Promise<number>;
  delete(key: string): Promise<void>;
}

Framework Integration

Express

const { createExpressMiddleware } = require('@samahuja642/rate-limiter');

app.use(createExpressMiddleware({
  limiter,
  keyGenerator: (req) => req.ip,
  onLimitReached: (req, res) => {
    res.status(429).json({ error: 'Too many requests' });
  },
  skip: (req) => req.path === '/health',
  cost: (req) => req.path.includes('/expensive') ? 5 : 1
}));

Generic/Custom Framework

const { createGenericRateLimiter } = require('@samahuja642/rate-limiter');

const rateLimiter = createGenericRateLimiter({
  limiter,
  keyExtractor: (context) => context.userId,
  onSuccess: (context, result) => {
    context.setHeader('X-RateLimit-Remaining', result.remaining);
  },
  onFailure: (context, result) => {
    context.sendError(429, 'Rate limit exceeded');
  }
});

// Use in your custom framework
const allowed = await rateLimiter(context);

Advanced Usage

Different Limits per Route

const authLimiter = new FixedWindow(storage, { maxRequests: 5, windowMs: 60000 });
const apiLimiter = new FixedWindow(storage, { maxRequests: 100, windowMs: 60000 });

app.post('/auth/login', createExpressMiddleware({ limiter: authLimiter }), loginHandler);
app.get('/api/data', createExpressMiddleware({ limiter: apiLimiter }), dataHandler);

User-Based Rate Limiting

app.use(createExpressMiddleware({
  limiter,
  keyGenerator: (req) => {
    // Rate limit by authenticated user ID
    return req.user?.id || req.ip;
  }
}));

Tiered Rate Limiting

app.use(createExpressMiddleware({
  limiter,
  cost: (req) => {
    // Premium users consume fewer tokens
    if (req.user?.tier === 'premium') return 0.5;
    if (req.user?.tier === 'free') return 2;
    return 1;
  }
}));

Custom Response Headers

app.use(createExpressMiddleware({
  limiter,
  onLimitReached: (req, res) => {
    res.status(429)
      .set('X-Custom-Header', 'Rate limited')
      .json({
        error: 'Too Many Requests',
        retryAfter: res.getHeader('Retry-After'),
        message: 'Please slow down your requests'
      });
  }
}));

API Reference

Rate Limiter Methods

All rate limiters implement:

// Consume tokens/requests
consume(key: string, tokens?: number): Promise<RateLimitResult>

// Get status without consuming
getStatus(key: string): Promise<RateLimitResult>

// Reset limit for a key
reset(key: string): Promise<void>

RateLimitResult

interface RateLimitResult {
  allowed: boolean;      // Whether request is allowed
  remaining: number;     // Tokens/requests remaining
  limit: number;         // Maximum limit
  resetTime: number;     // Unix timestamp when limit resets
  retryAfter?: number;   // Seconds to wait (when allowed is false)
}

HTTP Headers

Standard rate limit headers are automatically set:

  • X-RateLimit-Limit: Maximum requests allowed
  • X-RateLimit-Remaining: Requests remaining in current window
  • X-RateLimit-Reset: Unix timestamp when limit resets
  • Retry-After: Seconds to wait before retrying (when limit exceeded)

Testing

# Run all tests
npm test

# Run with coverage
npm run test:coverage

# Watch mode
npm run test:watch

Best Practices

  1. Choose the Right Algorithm

    • Use Fixed Window for simple cases
    • Use Leaky Bucket for traffic shaping
  2. Use Redis for Production

    • In-memory storage doesn't work across multiple instances
    • Redis provides persistence and distribution
  3. Set Appropriate Limits

    • Start conservative, increase based on monitoring
    • Different limits for different endpoints
    • Consider user tiers (free vs premium)
  4. Monitor and Adjust

    • Track rate limit hits
    • Adjust limits based on actual usage patterns
    • Log when limits are exceeded
  5. Fail Open on Errors

    • The middleware fails open by default (allows requests on errors)
    • Prevents outages due to storage issues

Examples

See the examples/ directory for complete working examples:

License

MIT © Samarth Ahuja

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support