Express Rate Limit
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.
Installation
- ``` shell
- # Using npm
- > npm install express-rate-limit
- # Using yarn or pnpm
- > yarn/pnpm add express-rate-limit
- ```
- ``` shell
- # Using npm
- > npm install https://github.com/express-rate-limit/express-rate-limit/releases/download/v{version}/express-rate-limit.tgz
- # Using yarn or pnpm
- > yarn/pnpm add https://github.com/express-rate-limit/express-rate-limit/releases/download/v{version}/express-rate-limit.tgz
- ```
Usage
Importing
- ``` ts
- const rateLimit = require('express-rate-limit')
- ```
- ``` ts
- import rateLimit from 'express-rate-limit'
- ```
Examples
- ``` ts
- import rateLimit from 'express-rate-limit'
- const limiter = rateLimit({
- windowMs: 15 * 60 * 1000, // 15 minutes
- max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
- standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
- legacyHeaders: false, // Disable the `X-RateLimit-*` headers
- })
- // Apply the rate limiting middleware to all requests
- app.use(limiter)
- ```
- ``` ts
- import rateLimit from 'express-rate-limit'
- const apiLimiter = rateLimit({
- windowMs: 15 * 60 * 1000, // 15 minutes
- max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
- standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
- legacyHeaders: false, // Disable the `X-RateLimit-*` headers
- })
- // Apply the rate limiting middleware to API calls only
- app.use('/api', apiLimiter)
- ```
- ``` ts
- import rateLimit from 'express-rate-limit'
- const apiLimiter = rateLimit({
- windowMs: 15 * 60 * 1000, // 15 minutes
- max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
- standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
- legacyHeaders: false, // Disable the `X-RateLimit-*` headers
- })
- app.use('/api/', apiLimiter)
- const createAccountLimiter = rateLimit({
- windowMs: 60 * 60 * 1000, // 1 hour
- max: 5, // Limit each IP to 5 create account requests per `window` (here, per hour)
- message:
- 'Too many accounts created from this IP, please try again after an hour',
- standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
- legacyHeaders: false, // Disable the `X-RateLimit-*` headers
- })
- app.post('/create-account', createAccountLimiter, (request, response) => {
- //...
- })
- ```
- ``` ts
- import rateLimit, { MemoryStore } from 'express-rate-limit'
- const apiLimiter = rateLimit({
- windowMs: 15 * 60 * 1000, // 15 minutes
- max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
- standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
- store: new MemoryStore(),
- })
- // Apply the rate limiting middleware to API calls only
- 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.
Troubleshooting Proxy Issues
- ``` ts
- app.set('trust proxy', numberOfProxies)
- ```
- ``` ts
- app.set('trust proxy', 1)
- app.get('/ip', (request, response) => response.send(request.ip))
- ```
Configuration
windowMs
number
max
number | function
- ``` ts
- const isPremium = async (user) => {
- // ...
- }
- const limiter = rateLimit({
- // ...
- max: async (request, response) => {
- if (await isPremium(request.user)) return 10
- else return 5
- },
- })
- ```
message
any
- ``` ts
- const isPremium = async (user) => {
- // ...
- }
- const limiter = rateLimit({
- // ...
- message: async (request, response) => {
- if (await isPremium(request.user))
- return 'You can only make 10 requests every hour.'
- else return 'You can only make 5 requests every hour.'
- },
- })
- ```
statusCode
number
legacyHeaders
boolean
Renamed in 6.x from headers to legacyHeaders.
standardHeaders
boolean
Renamed in 6.x from draft_polli_ratelimit_headers to standardHeaders.
requestPropertyName
string
skipFailedRequests
boolean
skipSuccessfulRequests
boolean
keyGenerator
function
- ``` ts
- const limiter = rateLimit({
- // ...
- keyGenerator: (request, response) => request.ip,
- })
- ```
NoteIf a keyGenerator returns the same value for every user, it becomes a global rate limiter. This could be combined with a second instance of express-rate-limit to have both global and per-user limits.
handler
function
- ``` ts
- const limiter = rateLimit({
- // ...
- handler: (request, response, next, options) =>
- response.status(options.statusCode).send(options.message),
- })
- ```
onLimitReached
function
skip
function
- ``` ts
- const allowlist = ['192.168.0.56', '192.168.0.21']
- const limiter = rateLimit({
- // ...
- skip: (request, response) => allowlist.includes(request.ip),
- })
- ```
- ``` ts
- const limiter = rateLimit({
- // ...
- skip: (request, response) => false,
- })
- ```
requestWasSuccessful
function
- ``` ts
- const limiter = rateLimit({
- // ...
- requestWasSuccessful: (request, response) => response.statusCode < 400,
- })
- ```
store
Store
Name | Description | Legacy/Modern |
---|---|---|
:--- | :--- | :--- |
memory-store | (default) Simple in-memory option. Does not share state when app has multiple processes or servers. | Modern as of v6.0.0 |
rate-limit-redis | A Redis-backed store, more suitable for large or demanding deployments. | Modern as of v3.0.0 |
rate-limit-memcached | A Memcached-backed store. | Legacy |
rate-limit-mongo | A MongoDB-backed store. | Legacy |
precise-memory-rate-limit | A memory store similar to the built-in one, except that it stores a distinct timestamp for each key. | Legacy |