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.
Alternate Rate-limiters
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. See the stores
section below for a list of external stores.
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
From the npm registry:
> npm install express-rate-limit
> yarn/pnpm add express-rate-limit
From Github Releases:
> npm install https://github.com/nfriedly/express-rate-limit/releases/download/v{version}/express-rate-limit.tgz
> yarn/pnpm add https://github.com/nfriedly/express-rate-limit/releases/download/v{version}/express-rate-limit.tgz
Replace {version}
with the version of the package that you want to your, e.g.:
6.0.0
.
Usage
This library is provided in ESM as well as CJS forms. To import it in a CJS
project:
const rateLimit = require('express-rate-limit')
To import it in a Typescript/ESM project:
import rateLimit from 'express-rate-limit'
Examples
To use it in an API-only server where the rate-limiter should be applied to all
requests:
import rateLimit from 'express-rate-limit'
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false,
})
app.use(limiter)
To use it in a 'regular' web server (e.g. anything that uses
express.static()
), where the rate-limiter should only apply to certain
requests:
import rateLimit from 'express-rate-limit'
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false,
})
app.use('/api', apiLimiter)
To create multiple instances to apply different rules to different endpoints:
import rateLimit from 'express-rate-limit'
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false,
})
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',
standardHeaders: true,
legacyHeaders: false,
})
app.post('/create-account', createAccountLimiter, (request, response) => {
})
To use a custom store:
import rateLimit from 'express-rate-limit'
import MemoryStore from 'express-rate-limit/memory-store.js'
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
store: new MemoryStore(),
})
app.use('/api', apiLimiter)
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.
Request API
A request.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.
The property name can be configured with the configuration option
requestPropertyName
Configuration options
windowMs
Time frame for which requests are checked/remembered. Also used in the
Retry-After
header when the limit is reached.
Note: with non-default stores, you may need to configure this value twice, once
here and once on the store. In some cases the units also differ (e.g. seconds vs
miliseconds)
Defaults to 60000
ms (= 1 minute).
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. If max
is a
function, it will be called with request
and response
params.
Defaults to 5
. Set to 0
to disable.
Example of using a function:
import rateLimit from 'express-rate-limit'
const isPremium = (request) => {
}
const limiter = rateLimit({
max: (request, response) => {
if (isPremium(request)) return 10
else return 5
},
})
app.use(limiter)
message
Error message sent to user when max
is exceeded.
May be a string
, JSON object, or any other value that Express's
response.send method
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
.
Renamed in 6.x
from headers
to legacyHeaders
.
standardHeaders
Enable headers conforming to the
ratelimit standardization draft
adopted by the IETF: RateLimit-Limit
, RateLimit-Remaining
, and, if the store
supports it, RateLimit-Reset
. May be used in conjunction with, or instead of
the legacyHeaders
option.
This setting also enables the Retry-After
header when max
is exceeded.
Defaults to false
(for backward compatibility), but recommended to use.
Renamed in 6.x
from draft_polli_ratelimit_headers
to standardHeaders
.
keyGenerator
Function used to generate keys.
Defaults to request.ip
, similar to this:
const keyGenerator = (request ) => request.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/route. Finally, the options
param has all
of the options that originally passed in when creating the current limiter and
the default values for other options.
The request.rateLimit
object has limit
, current
, and remaining
number of
requests and, if the store provides it, a resetTime
Date object.
Defaults to:
const handler = (request, response, next, options) => {
response.status(options.statusCode).send(options.message)
}
requestWasSuccessful
Function that is called when skipFailedRequests
and/or
skipSuccessfulRequests
are set to true
. May be overridden if, for example, a
service sends out a 200 status code on errors.
Defaults to
const requestWasSuccessful = (request, response) => response.statusCode < 400
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 triggered 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 (whitelist) requests. Returning true
, or a promise that
resolves with true
, from the function will skip limiting for that request.
Defaults to always false
(count all requests):
const skip = () => false
requestPropertyName
The name of the property that contains the rate limit information to add to the
request
object.
Defaults to rateLimit
.
store
The storage to use when persisting rate limit attempts.
By default, the memory store is used.
Available data stores are:
You may also create your own store. It must implement the Store
interface as
follows:
import rateLimit, {
Store,
Options,
IncrementResponse,
} from 'express-rate-limit'
class SomeStore implements Store {
customParam!: string
windowMs!: number
constructor(customParam: string) {
this.customParam = customParam
}
init(options: Options): void {
this.windowMs = options.windowMs
}
async increment(key: string): Promise<IncrementResponse> {
return {
totalHits,
resetTime,
}
}
async decrement(key: string): Promise<void> {
}
async resetKey(key: string): Promise<void> {
}
async resetAll(): Promise<void> {
}
}
export default SomeStore
Instance API
resetKey(key)
Resets the rate limiting for a given key. An example use case is to allow users
to complete a captcha or whatever to reset their rate limit, then call this
method.
Issues and Contributing
If you encounter a bug or want to see something added/changed, please go ahead
and open an issue!
If you need help with something, feel free to
start a discussion!
If you wish to contribute to the library, thanks! First, please read
the contributing guide. Then you can pick up any issue and
fix/implement it!
License
MIT © Nathan Friedly