or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

configuration.mdindex.mdmiddleware.mdstores.md
tile.json

configuration.mddocs/

Configuration Options

This document provides comprehensive details on all configuration options available for express-rate-limit.

Core Configuration

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;
}

Time and Limit Configuration

windowMs

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
});

limit

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;
  }
});

Response Configuration

message

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}`;
  }
});

statusCode

Type: number
Default: 429

HTTP status code sent when rate limit is exceeded.

const limiter = rateLimit({
  statusCode: 429 // HTTP 429 Too Many Requests
});

handler

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
    });
  }
});

Header Configuration

legacyHeaders

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
});

standardHeaders

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
});

identifier

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"
});

Request Filtering

skipFailedRequests

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
});

skipSuccessfulRequests

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
});

requestWasSuccessful

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
  }
});

skip

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";
  }
});

Key Generation

keyGenerator

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;
  }
});

ipv6Subnet

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;
  }
});

Advanced Configuration

requestPropertyName

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();
});

passOnStoreError

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
});

validate

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
  }
});

Usage Examples

API Rate Limiting

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
});

Authentication Endpoint Protection

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
});

Dynamic Rate Limiting

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;
  }
});

Deprecated Options

The following options are deprecated but still supported for backward compatibility:

headers (DEPRECATED)

Type: boolean
Default: true
Replacement: Use legacyHeaders instead

// DEPRECATED - but still works
const limiter = rateLimit({
  headers: false
});

// RECOMMENDED
const limiter = rateLimit({
  legacyHeaders: false
});

max (DEPRECATED)

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.