Configurable TypeScript rate limiting middleware for Express and Hono. It supports fixed window, sliding window, and token bucket strategies, plus in-memory and Redis-compatible backends.
npm install @codex-zjs/rate-limiter-middlewareExpress, Hono, and ioredis are optional peer dependencies. Install only what your app uses.
The default limiter allows 100 requests per minute per IP address, uses the fixed-window strategy, and stores counters in memory:
import { createExpressRateLimiter } from "@codex-zjs/rate-limiter-middleware";
app.use(createExpressRateLimiter());When a request exceeds the limit, the middleware returns 429 and sets Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset.
import express from "express";
import { createExpressRateLimiter } from "@codex-zjs/rate-limiter-middleware";
const app = express();
app.use("/api", createExpressRateLimiter({
strategy: "sliding-window",
limit: 250,
windowMs: 60_000,
dimensions: ["route", "user", "ip"],
identifyUser: ({ request }) => request.user?.id
}));import { Hono } from "hono";
import { createHonoRateLimiter } from "@codex-zjs/rate-limiter-middleware";
const app = new Hono();
app.use("/api/*", createHonoRateLimiter({
strategy: "token-bucket",
limit: 100,
windowMs: 60_000,
dimensions: ["ip"]
}));Pass an ioredis client through redis or store. The package automatically detects Redis-like clients when backend is auto.
import Redis from "ioredis";
import { createRateLimiter } from "@codex-zjs/rate-limiter-middleware";
const redis = new Redis(process.env.REDIS_URL);
const limiter = createRateLimiter({
backend: "auto",
redis,
strategy: "fixed-window",
limit: 500,
windowMs: 60_000,
prefix: "payments-api"
});Use dimensions to decide how keys are built:
createExpressRateLimiter({
dimensions: ["route", "user", "ip"],
identifyUser: ({ request }) => request.session?.userId,
identifyRoute: ({ request }) => request.route?.path ?? request.path
});You can also provide keyGenerator for full control.
const limiter = createRateLimiter({ strategy: "token-bucket" });
const result = await limiter.check({
ip: "203.0.113.9",
route: "/v1/report",
userId: "user_123"
});
if (!result.allowed) {
console.log(result.retryAfter);
}npm install
npm testThe test suite covers all three strategies, memory and Redis-compatible stores, Express/Hono adapters, headers, custom keying, skip rules, and window expiry.