Rate Limit
Throttle by IP, user, route or endpoint
Rate limiting protects your API from abuse, brute-force and accidental hammering. Nucleus ships a Redis-backed limiter with three algorithms and independent budgets for public, private and — most importantly — sensitive auth routes.
Limits can be keyed by IP, by authenticated user, by endpoint, or any combination, so you can express rules like “5 logins per minute per IP” and “100 reads per minute per user” simultaneously. Standard rate-limit headers tell clients exactly where they stand.
Strategy#
Choose the algorithm and the Redis namespace. The sliding window is the most accurate and the sensible default for most APIs.
enabledbooleanOptionalTurn the limiter on. When off, no throttling is applied.
falsestrategy'sliding-window' | 'fixed-window' | 'token-bucket'OptionalThe counting algorithm. sliding-window smooths bursts across the window boundary; fixed-window is cheapest but allows edge bursts; token-bucket permits controlled bursting up to a refill rate.
sliding-window— Accurate, burst-resistant. Recommended.fixed-window— Cheapest; can allow 2× bursts at window edges.token-bucket— Allows bursts up to a bucket size, refilled over time.
'sliding-window'keyPrefixstringOptionalRedis key prefix for limiter counters — isolate multiple apps on one Redis.
Keying dimensions#
What a limit is counted against. Combine these to build precise rules — per-IP stops a single attacker, per-user stops a single account, per-endpoint isolates hot routes.
byIpbooleanOptionalCount requests per client IP.
byUserIdbooleanOptionalCount requests per authenticated user.
byEndpointbooleanOptionalTrack each endpoint separately so a busy route doesn't exhaust another's budget.
skipSuccessfulRequestsbooleanOptionalOnly count failures toward the limit. Perfect for login: legitimate success never burns budget, but repeated failures do.
Budgets#
Per-category limits. Each budget is a window (duration string) plus a max count. Auth routes get their own tighter budgets, and the most sensitive ones add a blockDuration that locks out a client after the limit is hit.
1{2 "rateLimit": {3 "enabled": true,4 "strategy": "sliding-window",5 "skipSuccessfulRequests": true,6 "byIp": true,7 "authRoutes": {8 "login": { "window": "1m", "max": 5, "blockDuration": "15m" },9 "register": { "window": "1h", "max": 10 }10 },11 "privateRoutes": { "window": "1m", "max": 120 }12 }13}authRoutesobjectOptionalBudgets for authentication endpoints: a shared default plus stricter per-route overrides. Each override is { window, max } and the sensitive ones add blockDuration — a cooldown that locks the client out after the limit trips.
windowstringOptionalDefault window applied to all auth routes, e.g. "1m".
maxnumberOptionalDefault max requests per window across auth routes.
login{ window?; max?; blockDuration? }OptionalOverride for POST /auth/login. blockDuration locks the client out after the limit trips, e.g. "15m".
register{ window?; max?; blockDuration? }OptionalOverride for POST /auth/register.
passwordReset{ window?; max?; blockDuration? }OptionalOverride for the password-reset request/confirm routes.
magicLink{ window?; max?; blockDuration? }OptionalOverride for magic-link issuance.
publicRoutes{ window?: string; max?: number }OptionalBudget applied to unauthenticated/public endpoints.
privateRoutes{ window?: string; max?: number }OptionalBudget applied to authenticated endpoints.
Response headers & allow/deny lists#
Control the feedback clients receive and carve out exceptions. Whitelisted clients bypass limits; blacklisted ones are always rejected.
headers{ remaining?; reset?; limit? }OptionalCustom names for the rate-limit response headers (remaining quota, reset time, total limit) so clients can back off gracefully.
whiteliststring[]OptionalIdentifiers (e.g. IPs) that bypass rate limiting entirely.
blackliststring[]OptionalIdentifiers that are always blocked, regardless of budget.
Under the hood — the limiter#
Every counter lives in Redis (keyed by prefix + category + auth-type + the enabled ip/user/endpoint dimensions), so limits hold across instances. The three strategies differ only in how they count.
sliding-windowtimestamp listOptionalKeeps the timestamps of recent hits and drops any older than the window on each check — a precise rolling count with no bucket-boundary bursts. The default strategy.
fixed-windowper-bucket counterOptionalIncrements a counter keyed by the current window id (now / windowMs). Cheapest, but allows up to 2× max across a boundary.
token-bucketrefill rateOptionalRefills tokens at max/window and spends one per request, allowing controlled bursts up to the bucket size while smoothing the sustained rate.
lockout (blockDuration):blocked keyOptionalWhen an auth route with a blockDuration trips its limit, a {key}:blocked marker is written with an until timestamp; subsequent requests are refused with a retryAfter until it expires — so brute-forcing login costs the attacker a real lockout, not just a slow drip.
skipSuccessfulRequestsrefundOptionalWhen enabled, a request that ultimately succeeds is refunded (a timestamp popped / the counter decremented), so only failed attempts erode the budget — ideal for login where you want to punish wrong passwords, not correct ones.
allow/deny matchingglobOptionalwhitelist and blacklist entries support * wildcards (compiled to a regex). Whitelisted IPs bypass entirely; blacklisted IPs are refused for 24h before any counting happens.
Related sections