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

@rajatdebnath/limtr

v1.0.4

Published

An ultra-fast, extensible, framework-agnostic rate limiting engine for Node.js.

Downloads

375

Readme

Limtr 🚀

NPM Version CI Status License: MIT

An ultra-fast, highly extensible, framework-agnostic rate limiting engine for Node.js.

Built for modern enterprise systems, Limtr provides flawless atomic race-condition prevention via Redis Lua scripts, zero-dependency background garbage collection for memory stores, and mathematically precise Token Bucket algorithms.


📦 Installation

npm install @rajatdebnath/limtr

If you plan to use the Redis Store for distributed environments, you will also need to install the official redis client:

npm install redis

⚡ Quick Start

Limtr is totally framework-agnostic, but comes with a lightning-fast Express.js adapter out of the box.

import express from 'express';
import { expressRateLimit } from '@rajatdebnath/limtr';

const app = express();

// Set up a global rate limiter (100 requests per 15 minutes)
const limiter = expressRateLimit({
  algorithm: { name: 'tokenBucket', capacity: 100, refillRate: 100, refillInterval: 15 * 60 * 1000 }
});

app.use(limiter);

app.get('/', (req, res) => res.send('Protected by Limtr!'));
app.listen(3000);

🧠 Core Architecture

Limtr is broken down into three totally decoupled layers:

  1. The Store: Where bucket state is saved (MemoryStore or RedisStore).
  2. The Algorithm: The mathematical formula used to evaluate limits (fixedWindow or tokenBucket).
  3. The Engine: The central orchestrator that handles configurations, events, metrics, and plugins.

🛠️ Configuration Options

Limtr exposes an incredibly powerful configuration object.

| Option | Type | Default | Description | |--------|------|---------|-------------| | store | Store | MemoryStore | The database layer handling state. | | algorithm | Object | tokenBucket | The algorithm used for rate limiting (see below). | | keyGenerator | Function | req.ip | Returns a unique string identifier for the user. | | failStrategy | Object | FALLBACK | Behavior when the Store crashes (OPEN, CLOSED, FALLBACK). | | headers.enabled | Boolean | true | Injects standard X-RateLimit-* headers into the HTTP response. | | routes | Array | [] | Override global configs for specific Regex URL paths. | | plugins | Array | [] | Array of custom lifecycle plugins. | | metrics | Object | null | A MetricsCollector interface (e.g. for Prometheus). |

Built-in Presets

Don't want to configure everything manually? Limtr exports production-ready presets:

import { expressRateLimit, presets } from '@rajatdebnath/limtr';

// Instantly protect a login route from brute force
app.post('/login', expressRateLimit(presets.login), loginController);

🌐 Redis Setup (Distributed Limiting)

If you have multiple Node.js instances sitting behind a load balancer, using MemoryStore will result in inaccurate limits because state isn't shared across servers.

Limtr solves this with a highly optimized RedisStore powered by atomic Lua scripts that completely eliminate database race conditions.

import { expressRateLimit, RedisStore } from '@rajatdebnath/limtr';
import { createClient } from 'redis';

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

const limiter = expressRateLimit({
  store: new RedisStore(redisClient, 'limtr:prod:'),
  algorithm: { name: 'tokenBucket', capacity: 50, refillRate: 50, refillInterval: 1000 }
});

🚀 Production Examples

Advanced Token Bucket (Bursty API Traffic)

Limtr defaults to the Token Bucket algorithm, which mathematically smooths out "bursts" of traffic, making it ideal for heavy SaaS APIs. You can easily configure its burst capacity and refill rates:

const apiLimiter = expressRateLimit({
  algorithm: { 
    name: 'tokenBucket', 
    capacity: 1000,        // Max burst size
    refillRate: 100,       // Tokens to refill
    refillInterval: 1000   // Refill every 1 second
  }
});

Route-Level Overrides

You don't need a million middleware instances! Define global limits, and override them for specific paths.

const smartLimiter = expressRateLimit({
  algorithm: { name: 'tokenBucket', capacity: 100, refillRate: 100, refillInterval: 60000 },
  routes: [
    {
      pattern: /^\/api\/heavy-query/,
      algorithm: { name: 'tokenBucket', capacity: 5, refillRate: 5, refillInterval: 60000 }
    }
  ]
});

🔌 Events, Metrics, and Plugins

Limtr is built for enterprise observability.

Events

The underlying Engine extends Node.js EventEmitter. Access it directly to push alerts without blocking the HTTP request!

const rateLimiter = expressRateLimit({ ... });

rateLimiter.engine.on('requestBlocked', (payload) => {
  console.log(`Blocked IP: ${payload.key} at ${payload.timestamp}`);
});

Metrics (Prometheus / OpenTelemetry)

Pass a MetricsCollector interface into the config, and Limtr will automatically execute it.

const prometheusCollector = {
  recordBlocked: (reqDetails) => myPrometheusCounter.inc({ path: reqDetails.path })
};

const limiter = expressRateLimit({ metrics: prometheusCollector });

🩺 Troubleshooting

Q: Why am I getting "Too Many Requests" after only a few clicks? If you are behind a proxy (like Nginx or Cloudflare), Express might see the Proxy's IP address instead of the actual user's IP. Ensure you enable app.set('trust proxy', 1); in Express.

Q: My Redis instance crashed and now every request is blocked! By default, Limtr uses the FALLBACK fail-strategy. This means if Redis goes down, Limtr seamlessly degrades to local memory tracking. If you are experiencing blocks during an outage, ensure your failStrategy.mode is NOT set to CLOSED.

Q: RedisStore is throwing a NOSCRIPT error. This means Redis purged its script cache. Limtr's RedisStore automatically handles this by falling back to EVAL, but ensure you are using a standard version of Redis 6.0+.


❓ FAQ

Is it safe to use MemoryStore in production? Yes, but only for single-instance Node.js applications. Limtr's MemoryStore uses a non-blocking setInterval Garbage Collector and hard LRU ceilings to completely eliminate memory leaks and event-loop blocking. However, if you use a cluster or load balancer, you must use RedisStore.

Can I create a custom algorithm? Absolutely. The architecture is totally decoupled. Just create an object that implements the AlgorithmConfig JSDoc signature.

Does this work with Fastify or Koa? The core engine (Limiter.js) is 100% framework-independent. While the package currently only bundles an expressRateLimit adapter, you can easily wrap the core engine in a Fastify hook!