Skip to content

Repository files navigation

@iuashrafi/rate-limiter

A distributed rate limiting library for Node.js and TypeScript — five algorithms, two storage backends, and an Express middleware, all sharing the same pluggable interfaces so any algorithm works with any storage backend without modification.

  • Algorithms: fixed window, sliding window log, sliding window counter, token bucket, leaky bucket
  • Storage: in-memory (single process) or Redis (distributed, via atomic Lua scripts)
  • Middleware: drop-in Express integration with X-RateLimit-* and IETF-draft RateLimit-* headers

This project was built phase-by-phase as a teaching tool first, a library second — every algorithm and storage backend has a companion docs/phase-N/LEARN.md explaining the concept from first principles, and an ARCHITECTURE.md with the design decisions and trade-offs behind it. See docs/ for the full write-ups.

Install

npm install @iuashrafi/rate-limiter

express and ioredis are optional peer dependencies — only install them if you're using the Express middleware and/or RedisStore, respectively:

npm install express        # only if using rateLimit()
npm install ioredis        # only if using RedisStore

Quick start — in-memory, single process

import { MemoryStore, TokenBucketRateLimiter } from '@iuashrafi/rate-limiter';

const limiter = new TokenBucketRateLimiter(new MemoryStore(), {
  capacity: 10,
  refillRatePerSec: 1,
});

const result = await limiter.check('user-123');
// { allowed: true, remaining: 9, resetAt: 1735689660000 }

Distributed — Redis-backed

import { Redis } from 'ioredis';
import { RedisStore, FixedWindowRateLimiter } from '@iuashrafi/rate-limiter';

const client = new Redis(process.env.REDIS_URL);
const store = new RedisStore({ client }); // failOpen: true to allow traffic through on a Redis outage

const limiter = new FixedWindowRateLimiter(store, {
  windowSizeInSec: 60,
  maxRequests: 100,
});

const result = await limiter.check('user-123');

Every algorithm works against either storage backend without any code changes — swap MemoryStore for RedisStore to go from single-process to distributed.

Express middleware

import express from 'express';
import { MemoryStore, FixedWindowRateLimiter, rateLimit } from '@iuashrafi/rate-limiter';

const limiter = new FixedWindowRateLimiter(new MemoryStore(), {
  windowSizeInSec: 60,
  maxRequests: 100,
});

const app = express();
app.use(
  rateLimit({
    limiter,
    limit: 100, // must match the limiter's own configured max — see docs/phase-6/ARCHITECTURE.md ADR-023
    keyGenerator: (req) => req.ip, // default; override with an API key, user ID, etc.
    headers: 'both', // 'legacy' | 'draft' | 'both' | false
  }),
);

A blocked request gets a 429 with Retry-After, X-RateLimit-*, and RateLimit-* headers set. An allowed request gets the same rate-limit headers attached and falls through to your route.

Algorithms

Algorithm Storage interface Best for
FixedWindowRateLimiter IStorage simplest, cheapest — allows boundary bursts
SlidingWindowLogRateLimiter ILogStorage exact, no boundary burst — highest memory cost
SlidingWindowCounterRateLimiter IStorage & IWeightedCounterStorage good approximation, fixed-window-like cost
TokenBucketRateLimiter ITokenBucketStorage smooths bursts, allows some burst by design
LeakyBucketRateLimiter ILeakyBucketStorage strict, constant output rate

See each algorithm's docs/phase-N/LEARN.md for the full trade-off discussion and worked examples.

Benchmarking

npm run benchmark

Runs an in-process MemoryStore vs. RedisStore micro-benchmark (the Redis section is skipped with a message if no Redis is reachable at REDIS_URL, default redis://127.0.0.1:6379) and an end-to-end autocannon HTTP throughput test against a minimal Express app with rateLimit() installed.

Development

npm test              # run tests
npm run test:coverage # run tests with coverage
npm run lint           # lint
npm run build          # compile to dist/

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages