Integrations
Elysia
Elysia
Rate limiting plugin for Elysia (>=1.1 <2), powered by any RateLock engine.
- Engine-agnostic: bring a
@ratelock/local,@ratelock/redisor@ratelock/postgreslimiter - Bun-first synergy: pairs naturally with the native Bun Redis driver of
@ratelock/redis - Lazy initialization: pass a factory and the engine starts on the first matched request
- Dual-family headers:
RateLimit-*(RFC 9331) andX-RateLimit-*, configurable - Global hook: applies to every route of the instance through
onBeforeHandle
Installation
pnpm add @ratelock/elysia @ratelock/redisQuick start
import { Elysia } from 'elysia'
import { rateLimit } from '@ratelock/elysia'
import { fixedWindow } from '@ratelock/redis'
const app = new Elysia().use(
rateLimit({
// Lazy factory: nothing initializes until the first request
limiter: () => fixedWindow({ url: process.env.REDIS_URL!, limit: 100, windowMs: 60_000 }),
limit: 100,
keyGenerator: ({ request }) => request.headers.get('x-user-id') ?? 'anon',
})
)Already have an instance? Pass it directly:
const limiter = await fixedWindow({ limit: 100, windowMs: 60_000 })
new Elysia().use(rateLimit({ limiter }))Options
| Option | Type | Default | Description |
|---|---|---|---|
limiter | Limiter | (() => Limiter | Promise<Limiter>) | required | Any RateLock limiter. A factory is memoized and invoked once, on the first matched request. |
keyGenerator | (context) => string | Promise<string> | Bun requestIP | Identifier the request is counted against; falls back to a shared 'anonymous' bucket when unknown. |
headers | 'both' | 'rfc' | 'legacy' | false | 'both' | Header families attached to responses. |
limit | number | (none) | Quota, used only to emit the *Limit headers. |
denyStatusCode | number | 429 | Status returned on exhaustion. |
message | string | 'Too Many Requests' | JSON body of denial responses. |
Response headers
| Family | Headers |
|---|---|
| RFC 9331 | RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset |
| Legacy | X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset |
| Denial only | Retry-After |
RateLimit-Reset is always in seconds. Token bucket results project floor(tokens) onto *Remaining and the refill time onto Reset.
Identifiers behind proxies
The default identifier reads the Bun server's requestIP(request). Behind a load balancer, that address is your proxy's, so all clients would share one bucket. Configure your deployment or provide a keyGenerator. Never read raw x-forwarded-for yourself: attackers forge it per-request to bypass limits entirely.
How is this guide?
Last updated on