hono-rate-limiter

Rate limiting middleware for Hono with pluggable memory, Redis, Cloudflare, and Unstorage backends, plus WebSocket support.

Library
npm
v0.5.4
652stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
64/100Good
Development Activity72
Maintenance56
Community40
Maturity48
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
72/100Good
Architecture78
Code Quality82
Innovation62
Learning Curve65

hono-rate-limiter is a rate-limiting middleware built specifically for the Hono web framework, giving Hono apps a drop-in way to cap how many requests a client can make in a given time window. It ships a MemoryStore for single-instance deployments out of the box, and pluggable RedisStore, UnstorageStore, and Cloudflare Rate Limiting binding integrations for distributed or edge environments where in-process memory isn’t shared across instances.

Beyond plain HTTP middleware, the library also exports a webSocketLimiter that throttles inbound WebSocket messages using the same store abstraction, decrementing hit counts correctly based on whether the message handler succeeded or threw. It implements both the draft-6 and draft-7 IETF RateLimit-* header specifications, sets Retry-After on rejection, and lets callers configure custom key generation, skip logic, and success/failure classification to fit their own auth and observability setup.

What You Get

  • A rateLimiter() middleware factory that plugs directly into any Hono app’s middleware chain
  • Four store backends out of the box: MemoryStore (default), RedisStore (Lua-script atomic increments), UnstorageStore (any unstorage-compatible driver), and a Cloudflare Rate Limiting binding path
  • A webSocketLimiter() wrapper that rate-limits inbound WebSocket messages using the same store interface
  • Standardized RateLimit-* response headers for both the draft-6 and draft-7 IETF rate-limit-headers specs, plus Retry-After on rejection
  • Configurable keyGenerator, skip, requestWasSuccessful, and custom handler callbacks for full control over identification, exemptions, and rejection responses

Common Use Cases

  • Throttling public REST API endpoints built on Hono to a fixed number of requests per IP or API key within a time window
  • Protecting authentication routes (login, signup, password reset) from brute-force and credential-stuffing attempts
  • Sharing rate-limit state across multiple server instances or serverless invocations via the Redis or Unstorage store
  • Applying Cloudflare’s native Rate Limiting binding when deploying a Hono app to Cloudflare Workers
  • Capping the rate of inbound messages on a Hono WebSocket connection to prevent a single client from flooding the server

Under The Hood

Architecture The library is organized around a small Store interface (increment, decrement, get, resetKey, optional init/resetAll/shutdown) that every backend implements, and two middleware entry points — rateLimiter() in src/rateLimiter.ts and webSocketLimiter() in src/websocket.ts — that share the same increment/decrement/header-setting flow against whichever store is injected. rateLimiter() itself dispatches on whether a binding (Cloudflare Rate Limiting) is present, routing to either the generic honoRateLimiter path (store-backed, header-aware) or a thin cloudflareRateLimiter path that just forwards to the platform binding’s own limit() call. initStore() in src/utils.ts validates a store implements increment before wiring it up, keeping the core middleware decoupled from any specific storage technology — swapping MemoryStore for RedisStore or UnstorageStore requires no change to the middleware logic itself.

Tech Stack Written in TypeScript against Hono’s own Env/Input/MiddlewareHandler generic types (hono and unstorage are peer dependencies, not bundled), so the library adds no runtime framework dependency beyond Hono itself. The RedisStore talks to any redis-like client via injected Lua scripts (src/stores/redis/scripts.ts) executed through evalsha/scriptLoad, giving atomic increment/decrement without needing a specific Redis SDK pinned as a dependency. Builds are produced with pkgroll, dual ESM/CJS output is declared via exports conditions in package.json, and formatting/linting runs through Biome rather than ESLint/Prettier.

Code Quality The project has extensive test coverage relative to its size — seven Vitest spec files (middleware.spec.ts, store.spec.ts, headers.spec.ts, options.spec.ts, websockets.spec.ts, plus a dedicated redis/__tests__ suite for the store constructor and Lua-script behavior) totaling over 1,600 lines, run against a real @hono/node-server instance via supertest rather than pure mocks. Error handling is explicit: the Redis store attaches no-op .catch() handlers to script-load promises specifically to avoid unhandled-rejection crashes while still surfacing the original error to any caller that awaits them, and inline comments document non-obvious decisions like why onError in the WebSocket wrapper never decrements the hit counter. CI runs a dedicated test workflow plus CodeQL scanning, and Biome enforces lint/format rules on every commit via a Husky pre-commit hook.

What Makes It Unique Most rate-limiting middleware in the Node ecosystem targets Express; this library re-implements the same configurable model (windowed limits, pluggable stores, standard headers, skip/key-generator hooks) natively for Hono’s context-based middleware signature, while adding two things most equivalents lack out of the box: a Cloudflare Rate Limiting binding integration for edge/Workers deployments, and a WebSocket-specific limiter that rate-limits individual inbound messages on a persistent connection rather than just HTTP request/response cycles.

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