Rate Limiting in Fastify That Actually Works
@fastify/rate-limit + Redis is the production-grade combo. Here's the config that handles trust proxy, per-route limits, and per-user keys correctly.
Rate Limiting in Fastify That Actually Works
@fastify/rate-limit is the standard. Here's the production config.
Setup
npm install @fastify/rate-limit ioredis
import Fastify from 'fastify';
import rateLimit from '@fastify/rate-limit';
import Redis from 'ioredis';
const app = Fastify({ trustProxy: 1 });
await app.register(rateLimit, {
global: true,
max: 100,
timeWindow: '1 minute',
redis: new Redis(process.env.REDIS_URL),
keyGenerator: (req) => {
const user = (req).user; // if you've set this in an auth hook
return user?.id || req.ip;
},
skipOnError: true, // fail open if Redis is down
});
Per-route limits
Stricter on auth routes:
app.post('/auth/login', {
config: {
rateLimit: {
max: 5,
timeWindow: '5 minutes',
},
},
}, async (req, reply) => {
// login handler
});
What skipOnError does
When Redis is unreachable, the rate limiter fails open by default — requests pass through unrestricted. This prevents Redis becoming a hard dependency for your app's availability. Tradeoff: during a Redis outage, rate limits are temporarily disabled.
Verifying
for i in {1..15}; do curl -i http://localhost:3000/auth/login -d 'foo'; done
After the limit, you'll see 429 Too Many Requests with X-RateLimit-* headers indicating when to retry.
Related
Frequently Asked Questions
Does @fastify/rate-limit support per-route limits?
Yes — pass a config object to specific routes via `config.rateLimit`. Different limits per endpoint without separate plugin registrations.
Should I use the built-in store or Redis?
Redis for multi-instance. The built-in LRU store is in-memory and per-process.
What about per-user rate limiting?
Pass a `keyGenerator` function that returns the user ID for authenticated requests, falling back to IP.
Recommended reading
SecureNow 8.1 adds `securenow alerts rules create` — define your own detection rules from SQL, scope them to your apps, and ship them without leaving the terminal. Here's how, with a real magic-link brute-force example.
Jun 11A copy-paste prompt that lets an AI coding agent install SecureNow, wire Next.js instrumentation, verify traces and logs, deploy to AWS, simulate attacks, and prove firewall blocking with human approval gates.
May 18
If your team uses Sentry for frontend errors and needs backend distributed tracing without doubling the Sentry bill, here's the OpenTelemetry path that doesn't make you choose.
May 9