Express.js Rate Limiter
raw JSON →express-rate-limiter is a middleware for Express.js applications designed to control and limit incoming requests based on user IP addresses. It implements a dual-tier rate limiting strategy: an 'inner limit' to prevent rapid-fire requests (hammering) and an 'outer limit' to guard against general overuse. The current stable version is 1.3.1. While the package previously removed external dependencies for its storage mechanism, it now primarily utilizes an in-memory store, with a roadmap item to support pluggable database solutions like Redis. Key differentiators include its configurable dual-limit approach and automatic inclusion of standard X-RateLimit and Retry-After HTTP headers in responses when limits are exceeded. Releases appear somewhat irregular but indicate active maintenance through minor versions.
Common errors
error TypeError: Cannot read properties of undefined (reading 'middleware') ↓
var limiter = new Limiter({ db : new MemoryStore() }); is executed before app.use(limiter.middleware()); or similar calls. error Error: Missing db store in Limiter options. ↓
new Limiter({ db: new MemoryStore() }); or your custom store implementation. error TypeError: Limiter is not a constructor ↓
import Limiter from 'express-rate-limiter';. For CommonJS in Node.js, use const Limiter = require('express-rate-limiter');. Warnings
breaking Version 1.0.0 and 0.8.0 introduced significant refactoring to a plugin-based system for storage and removed `Memory-Cache` as a dependency. Users upgrading from pre-0.8.0 versions relying on the old caching mechanism or custom store implementations will need to update their code to conform to the new `store.js` interface. ↓
gotcha The `Limiter` constructor requires a `db` option to be explicitly provided; it does not have a default value. Failing to provide a database store (e.g., `new MemoryStore()`) will result in runtime errors. ↓
breaking In version 0.6.0, the `Retry-After` header's value was fixed to comply with HTTP guidelines. If previous client-side logic relied on the non-compliant value, it might behave differently after upgrading. ↓
gotcha The `pathLimiter` option, when enabled, prefixes the IP with a path for rate limiting, but if the `path` option is not explicitly set, the path will be read dynamically from the request. This can lead to unexpected rate limiting behavior if `path` is not consistently defined or if path segments vary. ↓
Install
npm install express-rate-limiter yarn add express-rate-limiter pnpm add express-rate-limiter Imports
- Limiter wrong
import { Limiter } from 'express-rate-limiter';correctimport Limiter from 'express-rate-limiter'; // OR (for CommonJS in Node.js) const Limiter = require('express-rate-limiter'); - MemoryStore wrong
import { MemoryStore } from 'express-rate-limiter';correctimport MemoryStore from 'express-rate-limiter/lib/memoryStore'; // OR (for CommonJS in Node.js) const MemoryStore = require('express-rate-limiter/lib/memoryStore'); - limiter.middleware wrong
app.post('/', limiter(), function(req, res) { ... });correctapp.post('/', limiter.middleware(), function(req, res) { ... });
Quickstart
import Limiter from 'express-rate-limiter';
import MemoryStore from 'express-rate-limiter/lib/memoryStore';
import express from 'express';
const app = express();
// Create a new Limiter instance, specifying the database store
const limiter = new Limiter({
db: new MemoryStore(),
innerLimit: 5, // Allow 5 calls per 1.5 seconds (default)
outerLimit: 100, // Allow 100 calls per 2 minutes (default)
innerTimeLimit: 1500, // 1.5 seconds
outerTimeLimit: 120000 // 2 minutes
});
// Apply the rate limiter middleware to a specific route
app.post('/api/data', limiter.middleware({ innerLimit: 10, headers: true }), (req, res) => {
res.status(200).send('Data successfully processed.');
});
// Apply the rate limiter globally
app.get('/public', limiter.middleware(), (req, res) => {
res.status(200).send('Public data accessible.');
});
// Start the server
const PORT = process.env.PORT ?? 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});