This document provides comprehensive details on all configuration options available for express-rate-limit.
interface Options {
windowMs: number;
limit: number | ValueDeterminingMiddleware<number>;
message: any | ValueDeterminingMiddleware<any>;
statusCode: number;
legacyHeaders: boolean;
standardHeaders: boolean | DraftHeadersVersion;
identifier: string | ValueDeterminingMiddleware<string>;
requestPropertyName: string;
skipFailedRequests: boolean;
skipSuccessfulRequests: boolean;
keyGenerator: ValueDeterminingMiddleware<string>;
ipv6Subnet: number | ValueDeterminingMiddleware<number> | false;
handler: RateLimitExceededEventHandler;
skip: ValueDeterminingMiddleware<boolean>;
requestWasSuccessful: ValueDeterminingMiddleware<boolean>;
store: Store | LegacyStore;
validate: boolean | EnabledValidations;
passOnStoreError: boolean;
}Type: number
Default: 60000 (1 minute)
Duration in milliseconds for which requests are checked/remembered.
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
limit: 100
});Type: number | ValueDeterminingMiddleware<number>
Default: 5
Maximum number of requests allowed during the window. Can be a static number or a function that dynamically determines the limit based on the request.
// Static limit
const limiter = rateLimit({
limit: 100
});
// Dynamic limit based on user type
const dynamicLimiter = rateLimit({
limit: async (req, res) => {
if (req.user?.isPremium) return 1000;
return 100;
}
});Type: any | ValueDeterminingMiddleware<any>
Default: "Too many requests, please try again later."
Response body sent when rate limit is exceeded. Can be a string, object, or function.
const limiter = rateLimit({
message: "Rate limit exceeded. Try again later.",
// or as JSON
message: {
error: "Too many requests",
retryAfter: "15 minutes"
},
// or as function
message: async (req, res) => {
return `Too many requests from ${req.ip}`;
}
});Type: number
Default: 429
HTTP status code sent when rate limit is exceeded.
const limiter = rateLimit({
statusCode: 429 // HTTP 429 Too Many Requests
});Type: RateLimitExceededEventHandler
Custom handler function called when rate limit is exceeded.
type RateLimitExceededEventHandler = (
request: Request,
response: Response,
next: NextFunction,
optionsUsed: Options,
) => void;const limiter = rateLimit({
handler: (req, res, next, options) => {
res.status(429).json({
error: "Rate limit exceeded",
limit: req.rateLimit.limit,
remaining: req.rateLimit.remaining,
resetTime: req.rateLimit.resetTime
});
}
});Type: boolean
Default: true
Enable legacy X-RateLimit-* headers for backward compatibility.
const limiter = rateLimit({
legacyHeaders: true // Enables X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
});Type: boolean | DraftHeadersVersion
Default: false
Enable standardized rate limit headers. Options: false, true (same as "draft-6"), "draft-6", "draft-7", "draft-8".
type DraftHeadersVersion = "draft-6" | "draft-7" | "draft-8";const limiter = rateLimit({
standardHeaders: "draft-7", // Enables RateLimit and RateLimit-Policy headers
legacyHeaders: false
});Type: string | ValueDeterminingMiddleware<string>
Default: Dynamic based on limit and window
Policy identifier used in draft-8 headers.
const limiter = rateLimit({
identifier: "api-access",
standardHeaders: "draft-8"
});Type: boolean
Default: false
Don't count requests that result in 4xx or 5xx status codes.
const limiter = rateLimit({
skipFailedRequests: true // Failed requests don't count toward limit
});Type: boolean
Default: false
Don't count requests that result in 2xx or 3xx status codes.
const limiter = rateLimit({
skipSuccessfulRequests: true // Only failed requests count toward limit
});Type: ValueDeterminingMiddleware<boolean>
Default: (req, res) => res.statusCode < 400
Custom logic to determine if a request was successful (used with skip options).
const limiter = rateLimit({
skipSuccessfulRequests: true,
requestWasSuccessful: (req, res) => {
return res.statusCode >= 200 && res.statusCode < 300; // Only 2xx are successful
}
});Type: ValueDeterminingMiddleware<boolean>
Default: () => false
Custom logic to determine if a request should be skipped entirely.
const limiter = rateLimit({
skip: (req, res) => {
// Skip requests from whitelisted IPs
return req.ip === "127.0.0.1";
}
});Type: ValueDeterminingMiddleware<string>
Default: IP-based with IPv6 subnet grouping
Function to generate unique keys for clients.
const limiter = rateLimit({
keyGenerator: (req, res) => {
// Use API key if available, otherwise IP
return req.headers['x-api-key'] || req.ip;
}
});Type: number | ValueDeterminingMiddleware<number> | false
Default: 56
IPv6 subnet mask for grouping IPv6 addresses. Common values: 32, 48, 56, 60, 64.
const limiter = rateLimit({
ipv6Subnet: 64, // More granular IPv6 grouping
// or disable IPv6 subnet grouping
ipv6Subnet: false,
// or dynamic based on request
ipv6Subnet: (req, res) => {
return req.headers['x-strict-limit'] ? 64 : 56;
}
});Type: string
Default: "rateLimit"
Property name where rate limit info is stored on the request object.
const limiter = rateLimit({
requestPropertyName: "rateLimitInfo"
});
// Access in middleware
app.use(limiter);
app.use((req, res, next) => {
console.log(req.rateLimitInfo.remaining);
next();
});Type: boolean
Default: false
Allow requests through if the store encounters an error.
const limiter = rateLimit({
store: externalStore,
passOnStoreError: true // Don't fail if external store is unavailable
});Type: boolean | EnabledValidations
Default: true
Configuration validation settings.
type EnabledValidations = {
default?: boolean; // Default validation setting for unlisted validations
ip?: boolean; // Validate IP address format and port presence
trustProxy?: boolean; // Check trust proxy configuration
xForwardedFor?: boolean; // Validate X-Forwarded-For header usage
forwardedHeader?: boolean; // Check for Forwarded header usage
positiveHits?: boolean; // Ensure hit counts are positive integers
unsharedStore?: boolean; // Prevent store instance sharing between limiters
singleCount?: boolean; // Prevent double-counting for same request
limit?: boolean; // Validate limit configuration
draftPolliHeaders?: boolean; // Check deprecated draft_polli_ratelimit_headers option
onLimitReached?: boolean; // Check deprecated onLimitReached option
headersDraftVersion?: boolean; // Validate header draft version
headersResetTime?: boolean; // Validate reset time for headers
validationsConfig?: boolean; // Validate the validation configuration itself
creationStack?: boolean; // Check if limiter created inside request handler
keyGeneratorIpFallback?: boolean; // Check for proper IPv6 handling in custom key generators
windowMs?: boolean; // Validate window duration for MemoryStore
};const limiter = rateLimit({
validate: {
trustProxy: true, // Validate proxy trust configuration
xForwardedFor: true, // Validate X-Forwarded-For header usage
ip: true, // Validate IP address format
default: false // Disable other validations
}
});const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
limit: 1000, // 1000 requests per window
message: {
error: "API rate limit exceeded",
retryAfter: 15 * 60 // seconds
},
standardHeaders: "draft-7",
legacyHeaders: false,
skipFailedRequests: true
});const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
limit: 5, // 5 attempts per window
message: "Too many authentication attempts",
skipSuccessfulRequests: true, // Only failed attempts count
keyGenerator: (req) => req.body.username || req.ip // Rate limit by username
});const dynamicLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
limit: async (req) => {
const user = await getUserFromToken(req.headers.authorization);
return user?.plan === 'premium' ? 1000 : 100;
},
keyGenerator: async (req) => {
const user = await getUserFromToken(req.headers.authorization);
return user?.id || req.ip;
}
});The following options are deprecated but still supported for backward compatibility:
Type: boolean
Default: true
Replacement: Use legacyHeaders instead
// DEPRECATED - but still works
const limiter = rateLimit({
headers: false
});
// RECOMMENDED
const limiter = rateLimit({
legacyHeaders: false
});Type: number | ValueDeterminingMiddleware<number>
Default: 5
Replacement: Use limit instead
// DEPRECATED - but still works
const limiter = rateLimit({
max: 100
});
// RECOMMENDED
const limiter = rateLimit({
limit: 100
});These deprecated options will be removed in a future major version. Update your code to use the recommended alternatives.