Express Rate Limit
Basic rate-limiting middleware for Express. Use to limit repeated requests to public APIs and/or endpoints such as password reset.
Plays nice with express-slow-down.
Note: this module does not share state with other processes/servers by default.
If you need a more robust solution, I recommend using an external store:
Stores
Alternate Rate-limiters
This module was designed to only handle the basics and didn't even support external stores initially. These other options all are excellent pieces of software and may be more appropriate for some situations:
Install
$ npm install --save express-rate-limit
Usage
For an API-only server where the rate-limiter should be applied to all requests:
const rateLimit = require("express-rate-limit");
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100
});
app.use(limiter);
For a "regular" web server (e.g. anything that uses express.static()
), where the rate-limiter should only apply to certain requests:
const rateLimit = require("express-rate-limit");
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100
});
app.use("/api/", apiLimiter);
Create multiple instances to apply different rules to different routes:
const rateLimit = require("express-rate-limit");
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100
});
app.use("/api/", apiLimiter);
const createAccountLimiter = rateLimit({
windowMs: 60 * 60 * 1000,
max: 5,
message:
"Too many accounts created from this IP, please try again after an hour"
});
app.post("/create-account", createAccountLimiter, function(req, res) {
});
Note: most stores will require additional configuration, such as custom prefixes, when using multiple instances. The default built-in memory store is an exception to this rule.
Typescript
Import the module like this:
import RateLimit = require("express-rate-limit");
Notice the mixture of import
and require
. This is typescript's way of importing modules that use the older commonjs default export style.
Request API
A req.rateLimit
property is added to all requests with the limit
, current
, and remaining
number of requests and, if the store provides it, a resetTime
Date object. These may be used in your application code to take additional actions or inform the user of their status.
There is also a helper function getRateLimit
on the default export, that safely returns the current rateLimit property from a request if it is availble. This is meant for typescript users mostly, since the express request type is not able to tell whether the rate limit is actually available.
Configuration options
max
Max number of connections during windowMs
milliseconds before sending a 429 response.
May be a number, or a function that returns a number or a promise.
Defaults to 5
. Set to 0
to disable.
windowMs
How long in milliseconds to keep records of requests in memory.
Defaults to 60000
(1 minute).
message
Error message sent to user when max
is exceeded.
May be a String, JSON object, or any other value that Express's res.send supports.
Defaults to 'Too many requests, please try again later.'
statusCode
HTTP status code returned when max
is exceeded.
Defaults to 429
.
Enable headers for request limit (X-RateLimit-Limit
) and current usage (X-RateLimit-Remaining
) on all responses and time to wait before retrying (Retry-After
) when max
is exceeded.
Defaults to true
.
keyGenerator
Function used to generate keys.
Defaults to req.ip:
function (req ) {
return req.ip;
}
handler
The function to handle requests once the max limit is exceeded. It receives the request and the response objects. The "next" param is available if you need to pass to the next middleware.
Thereq.rateLimit
object has limit
, current
, and remaining
number of requests and, if the store provides it, a resetTime
Date object.
Defaults to:
function (req, res, ) {
res.status(options.statusCode).send(options.message);
}
onLimitReached
Function that is called the first time a user hits the rate limit within a given window.
Thereq.rateLimit
object has limit
, current
, and remaining
number of requests and, if the store provides it, a resetTime
Date object.
Default is an empty function:
function (req, res, options) {
}
skipFailedRequests
When set to true
, failed requests won't be counted. Request considered failed when:
- response status >= 400
- requests that were cancelled before last chunk of data was sent (response
close
event triggered) - response
error
event was triggrered by response
(Technically they are counted and then un-counted, so a large number of slow requests all at once could still trigger a rate-limit. This may be fixed in a future release.)
Defaults to false
.
skipSuccessfulRequests
When set to true
successful requests (response status < 400) won't be counted.
(Technically they are counted and then un-counted, so a large number of slow requests all at once could still trigger a rate-limit. This may be fixed in a future release.)
Defaults to false
.
skip
Function used to skip requests. Returning true
from the function will skip limiting for that request.
Defaults to always false
(count all requests):
function () {
return false;
}
store
The storage to use when persisting rate limit attempts.
By default, the MemoryStore is used.
Available data stores are:
You may also create your own store. It must implement the following in order to function:
function SomeStore() {
this.incr = function(key, cb) {
cb(null, hits, resetTime);
};
this.decrement = function(key) {
};
this.resetKey = function(key) {
};
}
Instance API
instance.resetKey(key)
Resets the rate limiting for a given key. (Allow users to complete a captcha or whatever to reset their rate limit, then call this method.)
Summary of breaking changes:
v5 changes
- Removed index.d.ts. (See #138)
v4 Changes
- Express Rate Limit no longer modifies the passed-in options object, it instead makes a clone of it.
v3 Changes
- Removed
delayAfter
and delayMs
options; they were moved to a new module: express-slow-down. - Simplified the default
handler
function so that it no longer changes the response format. Now uses res.send. onLimitReached
now only triggers once for a given ip and window. only handle
is called for every blocked request.
v2 Changes
v2 uses a less precise but less resource intensive method of tracking hits from a given IP. v2 also adds the limiter.resetKey()
API and removes the global: true
option.
License
MIT © Nathan Friedly