# <div align="center"> Express Rate Limit </div>

---

Sponsored by [Zuplo](https://zuplo.link/express-rate-limit) a fully-managed API
Gateway for developers. Add
[dynamic rate-limiting](https://zuplo.link/dynamic-rate-limiting),
authentication and more to any API in minutes. Learn more at
[zuplo.com](https://zuplo.link/express-rate-limit)

---

<div align="center">

[![tests](https://github.com/express-rate-limit/express-rate-limit/actions/workflows/ci.yaml/badge.svg)](https://github.com/express-rate-limit/express-rate-limit/actions/workflows/ci.yaml)
[![npm version](https://img.shields.io/npm/v/express-rate-limit.svg)](https://npmjs.org/package/express-rate-limit 'View this project on NPM')
[![npm downloads](https://img.shields.io/npm/dm/express-rate-limit)](https://www.npmjs.com/package/express-rate-limit)

Basic rate-limiting middleware for [Express](http://expressjs.com/). Use to
limit repeated requests to public APIs and/or endpoints such as password reset.
Plays nice with
[express-slow-down](https://www.npmjs.com/package/express-slow-down).

</div>

## Use Cases

Depending on your use case, you may need to switch to a different
[store](#store).

#### Abuse Prevention

The default `MemoryStore` is probably fine.

#### API Rate Limit Enforcement

You likely want to switch to a different [store](#store). As a performance
optimization, the default `MemoryStore` uses a global time window, so if your
limit is 10 requests per minute, a single user might be able to get an initial
burst of up to 20 requests in a row if they happen to get the first 10 in at the
end of one minute and the next 10 in at the start of the next minute. (After the
initial burst, they will be limited to the expected 10 requests per minute.) All
other stores use per-user time windows, so a user will get exactly 10 requests
regardless.

Additionally, if you have multiple servers or processes (for example, with the
[node:cluster](https://nodejs.org/api/cluster.html) module), you'll likely want
to use an external data store to syhcnronize hits
([redis](https://npmjs.com/package/rate-limit-redis),
[memcached](https://npmjs.org/package/rate-limit-memcached), [etc.](#store))
This will guarentee the expected result even if some requests get handled by
different servers/processes.

### 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:

- [`rate-limiter-flexible`](https://www.npmjs.com/package/rate-limiter-flexible)
- [`express-brute`](https://www.npmjs.com/package/express-brute)
- [`rate-limiter`](https://www.npmjs.com/package/express-limiter)

## Installation

From the npm registry:

```sh
# Using npm
> npm install express-rate-limit
# Using yarn or pnpm
> yarn/pnpm add express-rate-limit
```

From Github Releases:

```sh
# 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
```

Replace `{version}` with the version of the package that you want to your, e.g.:
`6.0.0`.

## Usage

### Importing

This library is provided in ESM as well as CJS forms, and works with both
Javascript and Typescript projects.

**This package requires you to use Node 14 or above.**

Import it in a CommonJS project (`type: commonjs` or no `type` field in
`package.json`) as follows:

```ts
const { rateLimit } = require('express-rate-limit')
```

Import it in a ESM project (`type: module` in `package.json`) as follows:

```ts
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:

```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: 'draft-7', // draft-6: RateLimit-* headers; draft-7: combined RateLimit header
	legacyHeaders: false, // X-RateLimit-* headers
	// store: ... , // Use an external store for more precise rate limiting
})

// Apply the rate limiting middleware to all requests
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:

```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: 'draft-7', // Set `RateLimit` and `RateLimit-Policy`` headers
	legacyHeaders: false, // Disable the `X-RateLimit-*` headers
	// store: ... , // Use an external store for more precise rate limiting
})

// Apply the rate limiting middleware to API calls only
app.use('/api', apiLimiter)
```

To create multiple instances to apply different rules to different endpoints:

```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: 'draft-7', // draft-6: RateLimit-* headers; draft-7: combined RateLimit header
	legacyHeaders: false, // X-RateLimit-* headers
	// store: ... , // Use an external store for more precise rate limiting
})

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: 'draft-7', // draft-6: RateLimit-* headers; draft-7: combined RateLimit header
	legacyHeaders: false, // X-RateLimit-* headers
})

app.post('/create-account', createAccountLimiter, (request, response) => {
	//...
})
```

To use a custom store:

```ts
import { rateLimit } from 'express-rate-limit'
import RedisStore from 'rate-limit-redis'
import RedisClient from 'ioredis'

const redisClient = new RedisClient()
const rateLimiter = rateLimit({
	windowMs: 15 * 60 * 1000, // 15 minutes
	max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
	standardHeaders: 'draft-7', // draft-6: RateLimit-* headers; draft-7: combined RateLimit header
	legacyHeaders: false, // X-RateLimit-* headers
	store: new RedisStore({
		/* ... */
	}), // Use the external store
})

// Apply the rate limiting middleware to all requests
app.use(rateLimiter)
```

> **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

If you are behind a proxy/load balancer (usually the case with most hosting
services, e.g. Heroku, Bluemix, AWS ELB, Nginx, Cloudflare, Akamai, Fastly,
Firebase Hosting, Rackspace LB, Riverbed Stingray, etc.), the IP address of the
request might be the IP of the load balancer/reverse proxy (making the rate
limiter effectively a global one and blocking all requests once the limit is
reached) or `undefined`. To solve this issue, add the following line to your
code (right after you create the express application):

```ts
app.set('trust proxy', numberOfProxies)
```

Where `numberOfProxies` is the number of proxies between the user and the
server. To find the correct number, create a test endpoint that returns the
client IP:

```ts
app.set('trust proxy', 1)
app.get('/ip', (request, response) => response.send(request.ip))
```

Go to `/ip` and see the IP address returned in the response. If it matches your
public IP address, then the number of proxies is correct and the rate limiter
should now work correctly. If not, then keep increasing the number until it
does.

For more information about the `trust proxy` setting, take a look at the
[official Express documentation](https://expressjs.com/en/guide/behind-proxies.html).

## Configuration

### `windowMs`

> `number`

Time frame for which requests are checked/remembered. Also used in the
`Retry-After` header when the limit is reached.

Note: with stores that do not implement the `init` function (see the table in
the [`stores` section below](#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`

> `number | function`

The maximum number of connections to allow during the `window` before rate
limiting the client.

Can be the limit itself as a number or a (sync/async) function that accepts the
Express `request` and `response` objects and then returns a number.

Defaults to `5`. Set it to `0` to disable the rate limiter.

An example of using a 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`

The response body to send back when a client is rate limited.

May be a `string`, JSON object, or any other value that Express's
[`response.send`](https://expressjs.com/en/4x/api.html#res.send) method
supports. It can also be a (sync/async) function that accepts the Express
request and response objects and then returns a `string`, JSON object or any
other value the Express `response.send` function accepts.

Defaults to `'Too many requests, please try again later.'`

An example of using a function:

```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`

The HTTP status code to send back when a client is rate limited.

Defaults to `429` (HTTP 429 Too Many Requests - RFC 6585).

### `legacyHeaders`

> `boolean`

Whether to send the legacy rate limit headers for the limit
(`X-RateLimit-Limit`), current usage (`X-RateLimit-Remaining`) and reset time
(if the store provides it) (`X-RateLimit-Reset`) on all responses. If set to
`true`, the middleware also sends the `Retry-After` header on all blocked
requests.

Defaults to `true` (for backward compatibility).

> Renamed in `6.x` from `headers` to `legacyHeaders`.

### `standardHeaders`

> `boolean` | `'draft-6'` | `'draft-7'`

Whether to enable support for headers conforming to the
[RateLimit header fields for HTTP standardization draft](https://github.com/ietf-wg-httpapi/ratelimit-headers)
adopted by the IETF.

If set to `draft-6`, separate `RateLimit-Policy` `RateLimit-Limit`,
`RateLimit-Remaining`, and, if the store supports it, `RateLimit-Reset` headers
are set on the response, in accordance with
[draft-ietf-httpapi-ratelimit-headers-06](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-ratelimit-headers-06).

If set to `draft-7`, a combined `RateLimit` header is set containing limit,
remaining, and reset values, and a `RateLimit-Policy` header is set, in
accordiance with
[draft-ietf-httpapi-ratelimit-headers-07](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-ratelimit-headers-07).
`windowMs` is used for the reset value if the store does not provide a reset
time.

If set to `true`, it is treated as `draft-6`, however this behavior may change
in a future semver major release.

If set to any truthy value, the middleware also sends the `Retry-After` header
on all blocked requests.

The `standardHeaders` option may be used in conjunction with, or instead of the
`legacyHeaders` option.

ℹ️ Tip: use
[ratelimit-header-parser](https://www.npmjs.com/package/ratelimit-header-parser)
in clients to read/parse any form of express-rate-limit's headers.

Defaults to `false`.

> Renamed in `6.x` from `draft_polli_ratelimit_headers` to `standardHeaders`.

### `requestPropertyName`

> `string`

The name of the property on the Express `request` object to store the rate limit
info.

Defaults to `'rateLimit'`.

### `skipFailedRequests`

> `boolean`

When set to `true`, failed requests won't be counted. Request considered failed
when the `requestWasSuccessful` option returns `false`. By default, this means
requests fail when:

- the response status >= 400
- the request was cancelled before last chunk of data was sent (response `close`
  event triggered)
- the 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. PRs welcome!)

Defaults to `false`.

### `skipSuccessfulRequests`

> `boolean`

If `true`, the library will (by default) skip all requests that are considered
'failed' by the `requestWasSuccessful` function. By default, this means requests
succeed when the response status code < 400.

(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. PRs welcome!)

Defaults to `false`.

### `keyGenerator`

> `function`

Method to retrieve custom identifiers for clients, such as their IP address,
username, or API Key.

Should be a (sync/async) function that accepts the Express `request` and
`response` objects and then returns a string.

By default, the client's IP address is used:

```ts
const limiter = rateLimit({
	// ...
	keyGenerator: (request, response) => request.ip,
})
```

> **Note** If 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`

Express request handler that sends back a response when a client is
rate-limited.

By default, sends back the `statusCode` and `message` set via the `options`,
similar to this:

```ts
const limiter = rateLimit({
	// ...
	handler: (request, response, next, options) =>
		response.status(options.statusCode).send(options.message),
})
```

### `onLimitReached`

> `function`

A (sync/async) function that accepts the Express `request` and `response`
objects that is called the on the request where a client has just exceeded their
rate limit.

This method was
[deprecated in v6](https://github.com/express-rate-limit/express-rate-limit/releases/v6.0.0) -
Please use a custom `handler` that checks the number of hits instead.

### `skip`

> `function`

Function to determine whether or not this request counts towards a client's
quota. Should be a (sync/async) function that accepts the Express `request` and
`response` objects and then returns `true` or `false`.

Could also act as an allowlist for certain keys:

```ts
const allowlist = ['192.168.0.56', '192.168.0.21']

const limiter = rateLimit({
	// ...
	skip: (request, response) => allowlist.includes(request.ip),
})
```

By default, it skips no requests:

```ts
const limiter = rateLimit({
	// ...
	skip: (request, response) => false,
})
```

### `requestWasSuccessful`

> `function`

Method to determine whether or not the request counts as 'succesful'. Used when
either `skipSuccessfulRequests` or `skipFailedRequests` is set to true. Should
be a (sync/async) function that accepts the Express `request` and `response`
objects and then returns `true` or `false`.

By default, requests with a response status code less than 400 are considered
successful:

```ts
const limiter = rateLimit({
	// ...
	requestWasSuccessful: (request, response) => response.statusCode < 400,
})
```

### `validate`

> `boolean`

When enabled, a set of validation checks are run on the first request to detect
common misconfigurations with proxies, etc. Prints an error to the console if
any issue is detected.

Automatically disables after the first request is processed.

See https://github.com/express-rate-limit/express-rate-limit/wiki/Error-Codes
for more info.

Defaults to true.

### `store`

> `Store`

The `Store` to use to store the hit count for each client.

By default, the [`memory-store`](source/memory-store.ts) is used.

Here is a list of external stores:

| Name                                                                                   | Description                                                                                           | Legacy/Modern       |
| -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------- |
| [`memory-store`](source/memory-store.ts)                                               | _(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`](https://npmjs.com/package/rate-limit-redis)                       | A [Redis](http://redis.io/)-backed store, more suitable for large or demanding deployments.           | Modern as of v3.0.0 |
| [`rate-limit-memcached`](https://npmjs.org/package/rate-limit-memcached)               | A [Memcached](https://memcached.org/)-backed store.                                                   | Legacy              |
| [`rate-limit-mongo`](https://www.npmjs.com/package/rate-limit-mongo)                   | A [MongoDB](https://www.mongodb.com/)-backed store.                                                   | Legacy              |
| [`precise-memory-rate-limit`](https://www.npmjs.com/package/precise-memory-rate-limit) | A memory store similar to the built-in one, except that it stores a distinct timestamp for each key.  | Modern as of v2.0.0 |

Take a look at
[this guide](https://github.com/express-rate-limit/express-rate-limit/wiki/Creating-Your-Own-Store)
if you wish to create your own store.

## 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`.

## 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](https://github.com/nfriexpress-rate-limitedly/express-rate-limit/issues/new)!
If you need help with something, feel free to
[start a discussion](https://github.com/express-rate-limit/express-rate-limit/discussions/new)!

If you wish to contribute to the library, thanks! First, please read
[the contributing guide](contributing.md). Then you can pick up any issue and
fix/implement it!

## License

MIT © [Nathan Friedly](http://nfriedly.com/)
