Skip to content

@jfungus/ratelimit-express

Rate limiting middleware for Express - the most popular Node.js web framework.

Installation

Terminal window
npm install @jfungus/ratelimit-express

Basic Usage

import express from "express";
import { rateLimiter } from "@jfungus/ratelimit-express";
const app = express();
app.use(
rateLimiter({
limit: 100,
windowMs: 60 * 1000, // 1 minute
}),
);
app.get("/", (req, res) => res.send("Hello!"));
app.listen(3000);

Options

OptionTypeDefaultDescription
limitnumber | (req) => number60Max requests per window
windowMsnumber60000Window duration in ms
algorithm'fixed-window' | 'sliding-window''sliding-window'Algorithm
storeRateLimitStoreMemoryStoreStorage backend
keyGenerator(req) => stringIP-basedClient identifier
skip(req) => boolean-Skip rate limiting
handler(req, res, info) => void429 responseCustom handler
legacyHeadersbooleantrueSend X-RateLimit-* headers
standardHeadersbooleanfalseSend RateLimit-* headers

Access Rate Limit Info

app.get("/api/data", (req, res) => {
console.log(req.rateLimit);
// { limit: 100, remaining: 99, reset: 1234567890 }
res.json({ data: "hello" });
});

Custom Key Generator

Rate limit by user ID instead of IP:

app.use(
rateLimiter({
limit: 100,
windowMs: 60 * 1000, // 1 minute
keyGenerator: (req) => req.user?.id ?? req.ip ?? "anonymous",
}),
);

Custom Response

app.use(
rateLimiter({
limit: 100,
windowMs: 60 * 1000, // 1 minute
handler: (req, res, info) => {
res.status(429).json({
error: "Too Many Requests",
retryAfter: Math.ceil((info.reset - Date.now()) / 1000),
});
},
}),
);

Per-Route Limits

const apiLimiter = rateLimiter({ limit: 100, windowMs: 60 * 1000 }); // 1 minute
const authLimiter = rateLimiter({ limit: 5, windowMs: 60 * 1000 }); // 1 minute
app.use("/api/", apiLimiter);
app.use("/auth/", authLimiter);

Behind a Proxy

When behind nginx, AWS ELB, or similar:

app.set("trust proxy", 1);
app.use(
rateLimiter({
keyGenerator: (req) => req.ip, // Now correctly gets client IP
}),
);

With Redis

import { createStorage } from "unstorage";
import redisDriver from "unstorage/drivers/redis";
import { createUnstorageStore } from "@jfungus/ratelimit-unstorage";
const store = createUnstorageStore({
storage: createStorage({
driver: redisDriver({ url: process.env.REDIS_URL }),
}),
});
app.use(rateLimiter({ limit: 100, windowMs: 60 * 1000, store })); // 1 minute