@fastify/rate-limit

A low-overhead rate limiter for Fastify routes, with in-memory or Redis-backed request tracking.

Library
npm
v11.2.0
601stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
79/100Good
Development Activity68
Maintenance80
Community80
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
79/100Good
Architecture82
Code Quality88
Innovation60
Learning Curve85

@fastify/rate-limit is the official Fastify plugin for throttling incoming requests. It hooks into the request lifecycle (onRequest by default, or any other Fastify hook) to count requests per client within a rolling time window, and rejects requests over the limit with a 429 response and standard x-ratelimit-* headers (or IETF draft-spec headers on request).

Limits can be applied globally, per-route, or per-route-group, with support for async max/timeWindow functions, custom key generators (IP-based by default, with IPv6 subnet normalization), an allow-list, and a ban threshold that escalates repeat offenders to 403 responses. State is tracked in an in-process LRU cache by default, or in Redis via ioredis for multi-instance deployments, and the store interface is pluggable for custom backends like Knex or Sequelize.

What You Get

  • Global or per-route rate limiting with sane defaults (1000 requests / minute) and full override support
  • In-memory LRU store out of the box, or a Redis-backed store (via ioredis) for multi-instance deployments
  • IP-based key generation with IPv6 subnet normalization, or a fully custom sync/async keyGenerator
  • Ban escalation: return 403 instead of 429 once a client has exceeded the limit a configurable number of times
  • Standard x-ratelimit-* / retry-after response headers, or IETF draft-spec ratelimit-* headers
  • Pluggable store interface for custom persistence (examples included for Knex and Sequelize)

Common Use Cases

  • Protecting public API routes from abuse or scraping with per-IP request caps
  • Rate limiting login or password-reset endpoints to slow down brute-force attempts
  • Sharing rate-limit state across multiple server instances behind a load balancer via Redis
  • Rate limiting 404 handlers to prevent URL-guessing attacks
  • Applying different limits to different route groups (e.g. stricter limits on write endpoints)

Under The Hood

Architecture The plugin is a single Fastify plugin (index.js) registered via fastify-plugin so its decorators are visible outside its encapsulation context. On registration it normalizes global options (max, timeWindow, ban, allowList, header labels) into a globalParams object, chooses a store implementation (store/LocalStore.js backed by the toad-cache LRU, or store/RedisStore.js backed by ioredis, or a user-supplied store constructor), and decorates the Fastify instance with a rateLimit() preHandler factory plus a lower-level createRateLimit() helper used internally and exposed for advanced cases like rate-limiting the 404 handler. Per-route options passed to rateLimit() are merged over the global params at route-registration time, so each route/group can override max, timeWindow, keyGenerator, allowList, and header behavior independently while sharing one store instance per plugin scope.

Tech Stack Written in plain CommonJS Node.js with hand-written TypeScript type definitions (types/index.d.ts) validated by tstyche. Direct dependencies are fastify-plugin (encapsulation), @lukeed/ms (time-window string parsing), ip-address (IPv6 subnet normalization), and toad-cache (the in-memory LRU). The optional Redis store depends on ioredis as a peer/dev dependency, exercised in CI via fastify/workflows’ shared Redis-enabled plugin workflow. The example/ directory demonstrates custom stores backed by Knex (SQLite/MySQL) and Sequelize.

Code Quality Tests live under test/ as node:test files covering global/route/group rate limiting, IP normalization, exponential backoff, Redis-backed limiting, the not-found-handler pattern, and a set of regression tests tied to specific GitHub issues. c8 --100 enforces full statement/branch coverage on npm run test:unit, and tstyche separately validates the TypeScript definitions against index.tst.ts. Linting uses neostandard via eslint.config.js. CI runs through a shared, versioned Fastify org workflow (fastify/workflows/plugins-ci-redis.yml) with license checking and linting enabled.

What Makes It Unique Rather than bolting on a generic rate-limiting middleware, the plugin exposes its rate-check logic (createRateLimit) as a reusable Fastify decorator, letting it be composed into places outside normal route handling — such as rate-limiting a custom 404 handler to blunt URL-guessing attacks. The pluggable store interface (a small incr/child contract) means the same request-counting semantics, including exponential backoff and ban thresholds, work identically whether state lives in an in-process LRU or a shared Redis instance, without the application code changing.

Used by 5 apps in this directory

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search