Ratelock

Integrations

Elysia

Elysia

Rate limiting plugin for Elysia (>=1.1 <2), powered by any RateLock engine.

  • Engine-agnostic: bring a @ratelock/local, @ratelock/redis or @ratelock/postgres limiter
  • 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) and X-RateLimit-*, configurable
  • Global hook: applies to every route of the instance through onBeforeHandle

Installation

pnpm add @ratelock/elysia @ratelock/redis

Quick 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

OptionTypeDefaultDescription
limiterLimiter | (() => Limiter | Promise<Limiter>)requiredAny RateLock limiter. A factory is memoized and invoked once, on the first matched request.
keyGenerator(context) => string | Promise<string>Bun requestIPIdentifier 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.
limitnumber(none)Quota, used only to emit the *Limit headers.
denyStatusCodenumber429Status returned on exhaustion.
messagestring'Too Many Requests'JSON body of denial responses.

Response headers

FamilyHeaders
RFC 9331RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
LegacyX-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
Denial onlyRetry-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

On this page