Koa Rate Limit Middleware
koa-ratelimit is a robust rate limiting middleware designed for Koa web applications. The current stable version is 6.0.0. It provides essential functionality to control and restrict the frequency of client requests to prevent abuse, enhance security, and ensure fair resource usage. Developers can choose between an in-memory driver (using a JavaScript Map) for simple, single-instance deployments or a Redis driver (requiring an ioredis client) for scalable, distributed environments. Key configurable options include the duration of the rate limit window, the maximum number of requests allowed within that duration, custom error messages, and flexible request identification (e.g., by IP address). It also supports advanced features like whitelisting, blacklisting, and custom HTTP headers for communicating rate limit status to clients. Releases follow an evolutionary path, with recent major versions focusing on updated Node.js engine support and feature refinements.
Common errors
-
TypeError: db is not a Map instance or Redis client
cause The `db` option was either omitted or provided an invalid type for the configured `driver`.fixEnsure `db` is an instance of `Map` when `driver: 'memory'` or an `ioredis` client instance when `driver: 'redis'`. -
Error: Cannot find module 'ioredis'
cause The `ioredis` package is required for the Redis driver but was not installed in the project's dependencies.fixInstall `ioredis` explicitly: `npm install ioredis`. -
ReferenceError: Koa is not defined
cause The Koa framework itself was not imported or installed, which is necessary for the middleware to function within a Koa application.fixInstall `koa` and import it using `const Koa = require('koa');` at the top of your application file.
Warnings
- breaking Version 6.0.0 and above of `koa-ratelimit` explicitly require Node.js v18 or newer. Deployments on older Node.js environments will fail with engine incompatibility errors.
- gotcha The `Retry-After` HTTP header is automatically set in 429 'Too Many Requests' responses since `v5.1.0` when a limit is exceeded and an error is thrown. This provides clients with a standardized time (in seconds) to wait before retrying. Ensure your client-side error handling is prepared to interpret this header.
- gotcha The `onLimited` callback function, which allows custom logic to execute when a request is rate-limited, was fixed in `v6.0.0` to ensure correct functionality. If you were using this callback in earlier `v5.x` versions, its behavior might have been inconsistent or broken.
- gotcha The `db` option is mandatory and must be an appropriate instance for the chosen `driver` (`Map` for 'memory', `ioredis` client for 'redis'). Providing an incorrect or uninitialized `db` will lead to runtime errors when the middleware attempts to store or retrieve rate limit data.
Install
-
npm install koa-ratelimit -
yarn add koa-ratelimit -
pnpm add koa-ratelimit
Imports
- ratelimit
import ratelimit from 'koa-ratelimit';
const ratelimit = require('koa-ratelimit'); - Koa
import Koa from 'koa';
const Koa = require('koa'); - Redis
import { Redis } from 'ioredis';const Redis = require('ioredis');
Quickstart
const Koa = require('koa');
const ratelimit = require('koa-ratelimit');
const Redis = require('ioredis');
const app = new Koa();
// Initialize Redis client for rate limiting storage
const redisClient = new Redis();
// Apply rate limit middleware
app.use(ratelimit({
driver: 'redis',
db: redisClient, // Pass the ioredis client instance
duration: 60000, // 1 minute
errorMessage: 'You have sent too many requests. Please try again later.',
id: (ctx) => ctx.ip, // Identify clients by their IP address
headers: {
remaining: 'X-Rate-Limit-Remaining',
reset: 'X-Rate-Limit-Reset',
total: 'X-Rate-Limit-Total'
},
max: 100, // Max 100 requests per minute
disableHeader: false,
whitelist: (ctx) => {
// Example: allow localhost to bypass rate limiting
return ctx.ip === '127.0.0.1';
},
onLimited: (ctx) => {
console.log(`Rate limited IP: ${ctx.ip} for path ${ctx.path}`);
}
}));
// Response middleware for successful requests
app.use(async (ctx) => {
ctx.body = 'Hello, Koa! This is an un-rate-limited response.';
});
// Start the server
app.listen(3000,
() => console.log('Koa server listening on http://localhost:3000')
);