The Principal Dev – Masterclass for Tech Leads

The Principal Dev – Masterclass for Tech Leads28-29 May

Join

npm version npm node version deno version

Logo

node-rate-limiter-flexible

rate-limiter-flexible counts and limits the number of events and protects from DoS and brute force attacks at any scale.

It works with Valkey, Redis, Prisma, DynamoDB, process Memory, Cluster or PM2, Memcached, MongoDB, MySQL, SQLite, and PostgreSQL.

Memory limiter also works in the browser.

AI tools See llms.txt and CONTEXT.md for LLM-friendly documentation.

Atomic increments. All operations in memory or distributed environment use atomic increments against race conditions.

Fast. Average request takes 0.7ms in Cluster and 2.5ms in Distributed application. See benchmarks.

Flexible. Combine limiters, block key for some duration, delay actions, manage failover with insurance options, configure smart key blocking in memory and many others.

Ready for growth. It provides a unified API for all limiters. Whenever your application grows, it is ready. Prepare your limiters in minutes.

Friendly. No matter which node package you prefer: valkey-glide or iovalkey, redis or ioredis, sequelize/typeorm or knex, memcached, native driver or mongoose. It works with all of them.

In-memory blocks. Avoid extra requests to store with inMemoryBlockOnConsumed.

Deno compatible See this example

The Flexible Fixed Window algorithm starts counting from the moment a request is received, diversifying rate limit reset times across clients. Read more here

Installation

npm i --save rate-limiter-flexible

yarn add rate-limiter-flexible

Import

import { RateLimiterMemory } from "rate-limiter-flexible";

// or import directly
import RateLimiterMemory from "rate-limiter-flexible/lib/RateLimiterMemory.js";

Basic Example

Points can be consumed by IP address, user ID, authorisation token, API route or any other string.

const opts = {
  points: 6, // 6 points
  duration: 1, // Per second
};

const rateLimiter = new RateLimiterMemory(opts);

rateLimiter.consume(remoteAddress, 2) // consume 2 points
    .then((rateLimiterRes) => {
      // 2 points consumed
    })
    .catch((rateLimiterRes) => {
      // Not enough points to consume
    });

RateLimiterRes object

The Promise's resolve and reject callbacks both return an instance of the RateLimiterRes class if there is no error. Object attributes:

RateLimiterRes = {
    msBeforeNext: 250, // Number of milliseconds before next action can be done
    remainingPoints: 0, // Number of remaining points in current duration 
    consumedPoints: 5, // Number of consumed points in current duration 
    isFirstInDuration: false, // action is first in current duration 
}

You may want to set HTTP headers for the response:

const headers = {
  "Retry-After": rateLimiterRes.msBeforeNext / 1000,
  "X-RateLimit-Limit": opts.points,
  "X-RateLimit-Remaining": rateLimiterRes.remainingPoints,
  "X-RateLimit-Reset": Math.ceil((Date.now() + rateLimiterRes.msBeforeNext) / 1000)
}

Advantages:

Full documentation is on Wiki

Middlewares, plugins and other packages

Copy/paste examples on Wiki:

Migration from other packages

Docs and Examples

Changelog

See releases for detailed changelog.

Basic Options

Other options on Wiki:

See full list of options.

API

Read detailed description on Wiki.

Contributions

Appreciated, feel free!

Make sure you've launched npm run eslint before creating PR, all errors have to be fixed.

You can try to run npm run eslint-fix to fix some issues.

Any new limiter with storage must be extended from RateLimiterStoreAbstract. It has to implement 4 methods:

All other methods depend on the store. See RateLimiterRedis or RateLimiterPostgres for examples.

For wrapper classes that don't need full RateLimiterAbstract functionality, extend RateLimiterCompatibleAbstract instead. It requires implementing consume, penalty, reward, get, set, block, delete methods and blockDuration/execEvenly getters/setters. If the wrapper doesn't use blockDuration or execEvenly, empty no-op implementations can be provided. See RLWrapperBlackAndWhite for an example.

Note: all changes should be covered by tests.

Join libs.tech

...and unlock some superpowers

GitHub

We won't share your data with anyone else.