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

rate-guard

v1.0.0

Published

Lightweight, configurable Express rate limiting middleware with multiple algorithm support

Downloads

43

Readme

Rate Guard

A TypeScript rate limiting middleware for Express.js. Supports memory and Redis storage, Token Bucket and Fixed Window algorithms.

badges - build status - coverage to go here

Installation

npm install rate-guard

Quick Start

import express from "express";
import { createRateLimiter } from "rate-guard";

const app = express();

const limiter = createRateLimiter({
  storeType: "memory", // store type e.g memory or redis
  type: "tokenBucket", // choice of algo
  tokenLimit: 6, // 6 token limit within window
  timeFrame: 60000, // 1 minute
});

app.use(limiter);
app.get("/", (req, res) => res.send("Hello World!"));

app.listen(3000);

After exhausting your token limit, requests return 429 Too Many Requests.

Configuration

| Option | Type | Required | Default | Description | | -------------- | ---------------------------------- | -------- | --------------------- | ------------------------------------ | | storeType | 'memory' | 'redis' | Yes | - | Storage backend | | type | 'tokenBucket' | 'fixedWindow' | Yes | - | Rate limiting algorithm | | store | RedisClient | If Redis | - | Redis client instance | | tokenLimit | number | No | 50 | Requests allowed per window | | timeFrame | number | No | 900000 | Window length in ms (default 15 min) | | ttl | number | No | 86400000 | Data expiry in ms (default 24 hours) | | message | string | No | 'Too many requests' | Response message when limited | | keyGenerator | (req) => string | No | req.ip | Custom key resolver function |

Usage

Memory Store (Development)

const limiter = createRateLimiter({
  storeType: "memory",
  type: "tokenBucket",
  tokenLimit: 100,
  timeFrame: 60000,
});

Redis Store (Production)

import { createClient } from "redis";

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

const limiter = createRateLimiter({
  storeType: "redis",
  store: redis,
  type: "tokenBucket",
  tokenLimit: 100,
  timeFrame: 60000,
});

Per-Route Limiting

const strictLimiter = createRateLimiter({
  storeType: "memory",
  type: "tokenBucket",
  tokenLimit: 10,
  timeFrame: 60000,
});

const relaxedLimiter = createRateLimiter({
  storeType: "memory",
  type: "tokenBucket",
  tokenLimit: 100,
  timeFrame: 60000,
});

app.post("/login", strictLimiter, loginHandler);
app.get("/api", relaxedLimiter, apiHandler);

Per-Route Mix Limiting

const perUserLimiter = createRateLimiter({
  storeType: "memory",
  type: "tokenBucket",
  tokenLimit: 100,
  timeFrame: 60000,
});

app.get("/api", perUserLimiter, apiHandler); // Per-user limit

Custom Error Message

const limiter = createRateLimiter({
  storeType: "memory",
  type: "tokenBucket",
  tokenLimit: 100,
  timeFrame: 60000,
  message: "Slow down! Too many requests.",
});

Algorithms

Token Bucket

Per-user rate limiting with gradual token refill. Allows bursts while maintaining average rate.

  • Tokens refill gradually over time
  • Users can "save up" tokens for legitimate bursts
  • Key: client IP address
const limiter = createRateLimiter({
  storeType: "memory",
  type: "tokenBucket",
  tokenLimit: 60, // 60 tokens max
  timeFrame: 60000, // Refills completely in 60 seconds (1 token/sec)
});

Fixed Window

Per-user rate limiting with full reset at window expiry.

  • Tokens reset completely when window expires
  • Per-user by default (keyed by IP)
  • Key: client IP address (or custom via keyGenerator)
const limiter = createRateLimiter({
  storeType: "memory",
  type: "fixedWindow",
  tokenLimit: 1000, // 1000 requests per window per user
  timeFrame: 60000, // Window resets every 60 seconds
});

Comparison

| Feature | Token Bucket | Fixed Window | | -------------- | ----------------- | -------------------- | | Scope | Per-user | Per-user | | Refill | Gradual | Full reset | | Burst handling | Smooth | Edge spikes possible | | Use case | Sustained traffic | Simple request caps |

Storage Backends

Memory

  • Zero dependencies
  • Fast (in-process)
  • Single instance only
  • Good for development and small deployments

Redis

  • Distributed rate limiting
  • Works across multiple instances
  • Production ready
  • Requires Redis connection

Concurrency Note

The default implementation uses non-atomic read-modify-write operations. For strict rate limiting under high concurrency with Redis, consider wrapping with your own atomic store implementation using Lua scripts.

API

createRateLimiter(options)

Returns an Express middleware function.

type RateLimiterOptions =
  | {
      storeType: "memory";
      type: "tokenBucket" | "fixedWindow";
      tokenLimit?: number;
      timeFrame?: number;
      ttl?: number;
      message?: string;
      keyGenerator?: (req: unknown) => string | Promise<string>;
    }
  | {
      storeType: "redis";
      store: RedisClient;
      type: "tokenBucket" | "fixedWindow";
      tokenLimit?: number;
      timeFrame?: number;
      ttl?: number;
      message?: string;
      keyGenerator?: (req: unknown) => string | Promise<string>;
    };

Response Headers

All responses include rate limit headers:

| Header | Description | | ----------------------- | ---------------------------------- | | X-RateLimit-Remaining | Tokens remaining in current window | | X-RateLimit-Limit | Total token limit | | X-RateLimit-Reset | Window reset timestamp (ms) |

Rate Limited Response

When rate limited, returns:

HTTP 429 Too Many Requests
Content-Type: application/json

{ "message": "Too many requests" }

Roadmap

  • [ ] Sliding Window Log algorithm
  • [ ] Sliding Window Counter algorithm
  • [ ] Leaky Bucket algorithm
  • [x] Token Bucket algorithm
  • [x] Fixed Window algorithm
  • [x] Custom key resolver (keyGenerator option)
  • [ ] Automatic cleanup for memory store
  • [x] Rate limit headers (X-RateLimit-Remaining, X-RateLimit-Limit, X-RateLimit-Reset)
  • [ ] Usage statistics / monitoring hooks (until implemented, manage Redis data directly)

Author

Jack Tubby - GitHub

Contributing

Contributions welcome. Please open an issue first to discuss proposed changes.

License

MIT License