Skip to content

Express

Keep Express behavior outside the core limiter. The middleware translates a rate-limit decision into HTTP headers and a 429 response.

import type { RequestHandler } from 'express';
export const rateLimit: RequestHandler = async (request, response, next) => {
try {
const identifier = request.ip ?? 'unknown';
const result = await limiter.consume(identifier);
response.setHeader('RateLimit-Remaining', String(result.remaining));
response.setHeader('RateLimit-Reset', String(result.resetAt));
if (!result.allowed) {
response.setHeader('Retry-After', String(Math.ceil(result.retryAfterMs / 1000)));
response.status(429).json({ message: 'Too many requests' });
return;
}
next();
} catch (error) {
// Configuration and store errors from limix carry a stable `code` via
// RateLimiterConfigurationError / RateLimiterStoreError, so an Express
// error handler can distinguish them from unrelated application errors.
next(error);
}
};

Prefer authenticated user, tenant, or API-key identifiers where possible. IP addresses can represent many users behind a proxy and require careful trusted proxy configuration.