New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

flex-rate-limit

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

flex-rate-limit

Universal rate limiting module for Node.js - supports any framework, multiple storage backends, flexible algorithms

latest
Source
npmnpm
Version
2.2.5
Version published
Weekly downloads
49
13.95%
Maintainers
1
Weekly downloads
 
Created
Source

flex-rate-limit

A framework-agnostic Node.js rate limiting library with multiple algorithms, Memory / Redis / cache-hub backed storage, and Express-style middleware.

npm version License: Apache-2.0 Node.js Version

Documentation · 中文文档 · Examples

Why Use It

  • Framework-agnostic core: call check() from Express, Koa, Egg.js, Hapi, Fastify, workers, queues, or any custom adapter.
  • Express-style middleware: use limiter.middleware() directly in Express-compatible stacks.
  • Four algorithms: sliding window, fixed window, token bucket, and leaky bucket.
  • Multiple stores: in-memory storage, Redis storage, CacheHubStore, or your own store adapter.
  • Distributed-ready options: use Redis or cache-hub Redis atomic backends when counters must be shared across instances.
  • Standard metadata: each check returns allowed, limit, current, remaining, resetTime, and retryAfter.
  • Type definitions included: CommonJS, ESM, and TypeScript consumers are supported.

Requirements

  • Node.js >=18.0.0
  • npm, pnpm, or another package manager compatible with the npm registry
  • Redis is optional and only needed for Redis-backed distributed rate limiting

Installation

npm install flex-rate-limit

Redis-backed usage:

npm install flex-rate-limit ioredis

cache-hub atomic backend usage:

npm install flex-rate-limit cache-hub ioredis

Quick Start

Direct check()

const { RateLimiter } = require('flex-rate-limit');

const limiter = new RateLimiter({
  windowMs: 15 * 60 * 1000,
  max: 100,
});

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

if (!result.allowed) {
  console.log(`Retry after ${result.retryAfter} ms`);
}

Express Middleware

const express = require('express');
const { RateLimiter } = require('flex-rate-limit');

const app = express();

const globalLimiter = new RateLimiter({
  windowMs: 15 * 60 * 1000,
  max: 100,
});

app.use(globalLimiter.middleware());

const loginLimiter = new RateLimiter({
  windowMs: 15 * 60 * 1000,
  max: 5,
});

app.post('/api/login', loginLimiter.middleware(), (_req, res) => {
  res.json({ message: 'login accepted' });
});

app.listen(3000);

Koa, Egg.js, Hapi, Fastify, and Other Frameworks

Use check() and map the result to the framework's own middleware, hook, or pre-handler shape:

const { RateLimiter } = require('flex-rate-limit');

const limiter = new RateLimiter({
  windowMs: 60 * 1000,
  max: 60,
});

async function guard(ctx, next) {
  const key = `user:${ctx.user?.id || ctx.ip}:${ctx.path}`;
  const result = await limiter.check(key, { route: ctx.path });

  if (!result.allowed) {
    ctx.status = 429;
    ctx.body = { error: 'Too Many Requests', retryAfter: result.retryAfter };
    return;
  }

  await next();
}

See the runnable framework examples on GitHub and the quickstart guide.

Storage Backends

Memory Store

The default store is fast and simple. Use it for single-process services, local development, tests, and cases where counters do not need to be shared across instances.

const limiter = new RateLimiter({
  windowMs: 60 * 1000,
  max: 100,
  store: 'memory',
});

RedisStore

Use RedisStore when multiple application instances must share counters.

const Redis = require('ioredis');
const { RateLimiter, RedisStore } = require('flex-rate-limit');

const redis = new Redis(process.env.REDIS_URL || 'redis://127.0.0.1:6379');

const limiter = new RateLimiter({
  windowMs: 60 * 1000,
  max: 100,
  store: new RedisStore({ client: redis, prefix: 'rl:' }),
});

If you pass store: 'redis://...', RateLimiter creates and owns the Redis client; call await limiter.close() during shutdown. When you pass your own Redis client to RedisStore, that client remains caller-owned unless you set ownsClient: true.

CacheHubStore

CacheHubStore keeps flex-rate-limit as the algorithm and middleware layer while delegating high-concurrency state updates to cache-hub atomic primitives. Pass a Redis client for distributed production usage; omit the client only when an in-memory cache-hub backend is acceptable. The in-memory cache-hub path prunes expired rate-limit state automatically, and await limiter.close() closes store-owned cleanup timers or cache resources.

const Redis = require('ioredis');
const { RateLimiter, CacheHubStore } = require('flex-rate-limit');

const redis = new Redis(process.env.REDIS_URL || 'redis://127.0.0.1:6379');

const limiter = new RateLimiter({
  algorithm: 'sliding-window',
  windowMs: 60 * 1000,
  max: 100,
  store: new CacheHubStore({ client: redis, prefix: 'rl:' }),
});

Read more in the storage guide.

Algorithms

AlgorithmBest ForNotes
sliding-windowPrecise rolling limitsDefault algorithm; stores more per-key state
fixed-windowHigh-throughput coarse windowsFast, but requests can cluster around window boundaries
token-bucketControlled burstsAllows bursts up to capacity and refills over time
leaky-bucketSmoothing trafficDrains at a steady rate

Choose semantics first, then optimize storage and hot paths. See algorithm comparison and deep analysis.

Common Configuration

const limiter = new RateLimiter({
  windowMs: 60 * 1000,
  max: 100,
  algorithm: 'sliding-window',
  headers: true,
  keyGenerator: (req) => `user:${req.user?.id || req.ip}:${req.path}`,
  skip: (req) => req.path === '/health',
  handler: (req, res) => {
    res.status(429).json({ error: 'Too Many Requests' });
  },
  perRoute: {
    '/api/login': { max: 5, windowMs: 15 * 60 * 1000 },
    '/api/users': { max: 100, windowMs: 60 * 1000 },
  },
});
OptionDefaultDescription
windowMs60000Time window in milliseconds
max100Max requests per window; may be a function
algorithmsliding-windowOne of the four supported algorithms
storememoryStore instance or 'memory'
keyGeneratorIP-basedBuilds the rate-limit key from request context
skip() => falseReturn true to bypass rate limiting
handlerbuilt-in 429 responseCustom over-limit handler
headerstrueWrite X-RateLimit-* and Retry-After headers
perRoutenullRoute-specific overrides
skipSuccessfulRequestsfalseRoll back successful responses
skipFailedRequestsfalseRoll back failed responses

Full details are in the configuration guide and API reference.

Result Shape

{
  allowed: true,
  limit: 100,
  current: 1,
  remaining: 99,
  resetTime: 1767225600000,
  retryAfter: 0
}

Benchmarks

The repository includes reproducible local benchmark scripts for Memory direct checks, Redis direct checks, and HTTP middleware scenarios.

Run these from a cloned repository after installing development dependencies:

npm install
npm run benchmark:memory
npm run benchmark:redis
npm run benchmark:http

The npm runtime package does not require benchmark dependencies. Redis and HTTP benchmark output records the Node.js version, Redis URL, key distribution, concurrency, and other parameters. Use BENCH_JSON=1 when you need machine-readable output.

See Benchmark and Performance for commands, environment variables, and interpretation notes.

Documentation

EntryDescription
Documentation indexEnglish documentation navigation
Chinese documentationSimplified Chinese documentation navigation
QuickstartFirst integration path and framework examples
ConfigurationComplete option reference and practical presets
StorageMemory, Redis, and CacheHubStore selection
Business lock guideUser + route scoped rate limiting
Algorithm comparisonChoosing the right algorithm
API referenceClasses, options, stores, and exports
Benchmark guideLocal benchmark commands and caveats

The website is built with Rspress and reuses the docs/ directory:

npm run docs:dev
npm run docs:validate
npm run docs:build

Examples

Runnable examples are available on GitHub:

CategoryFiles
Quickstartquickstart-express.js, quickstart-koa.js, quickstart-egg.js, quickstart-hapi.js, quickstart-fastify.js
Router examplesexpress-router-example.js, koa-router-example.js, egg-router-example.js, fastify-router-example.js
IP whitelist examplesexpress-ip-whitelist-independent.js, koa-ip-whitelist-independent.js, ip-whitelist-example.js
Standalone usagestandalone-example.js
Business lockegg-business-lock-example.js

Development

npm test
npm run test:unit
npm run test:integration
npm run typecheck
npm run lint
npm run coverage

Troubleshooting

  • Counters are not shared across instances: use RedisStore or CacheHubStore with a Redis client instead of the default Memory store.
  • Redis benchmarks are skipped: start Redis locally or set REDIS_URL / BENCH_REDIS_URL.
  • Package installs but Redis code fails at runtime: install and configure a Redis client such as ioredis.
  • Short-lived scripts keep running after Redis usage: call await limiter.close() when using store: 'redis://...', or pass ownsClient: true to RedisStore if the store should close your client.
  • Koa/Fastify/Hapi integration feels awkward: call check() directly and wrap the result in the framework's native middleware or hook style.
  • Benchmark numbers differ from the docs or CI: local CPU, Node.js version, Redis latency, key distribution, and HTTP app work all affect throughput.

Support

License

Apache-2.0

Keywords

rate-limit

FAQs

Package last updated on 27 Jul 2026

Related posts