Rate limiting
rateLimit() counts calls with Effect's RateLimiter, in memory or in Redis, and sets the RateLimit headers.
On this page
rateLimit() counts calls with Effect's RateLimiter (effect/persistence). The store is a layer on the handler: layerStoreMemory for one instance, layerStoreRedis for many.
import { RateLimiter } from 'effect/persistence';
import { rateLimit } from '@trpc12/trpc/middleware';
const login = t.procedure
.use(
rateLimit<{ ctx: { ip: string } }>({
key: (opts) => `login:${opts.ctx.ip}`,
limit: 5,
window: '1 minute',
}),
)
.mutation(/* … */);
createFetchHandler({
router,
layer: RateLimiter.layer.pipe(Layer.provide(RateLimiter.layerStoreMemory)),
});Past the limit it fails with RateLimited (TOO_MANY_REQUESTS, 429, data: { limit, retryAfter } in milliseconds), and it sets RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset and Retry-After. onExceeded: 'delay' waits for capacity instead.
On the client
RateLimited is a typed error, so the client narrows on its code. retryLink({ retry, delayMs }) gets the error, so it can wait error.data.retryAfter (retryLink).