Rate limit

ingenium.rateLimit is a fixed-window rate limiter with an in-memory default store. The store interface is Promise-returning so a Redis-backed adapter fits cleanly.

Usage

app.use(ingenium.rateLimit({
  windowMs: 60_000,
  limit: 100,
  // default keygen reads X-Forwarded-For - make sure trustProxy is set!
  keyGenerator: (ctx) => ctx.ip,
  skip: (ctx) => ctx.path.startsWith('/health'),
}))

Behavior

  • Storage - fixed-window in-memory store (MemoryStore) by default. The cleanup interval is unref()'d so it never holds the event loop alive.
  • Pluggable - implement the RateLimitStore interface (Promise-returning) to back it with Redis or any other shared store.
  • Headers - sets X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset on every response.
  • 429 response - sets Retry-After on the rejection.

Note: The default keygen reads X-Forwarded-For via ctx.ip. Without trustProxy configured correctly, an attacker can spoof the header and bypass the limit. Set trustProxy before relying on rate limiting in production.

Multi-instance deploys

The in-memory store does not share state across pods. For multi-instance production, a Redis-backed adapter is the next P0 - see the roadmap.

Where to next?