Rate limit an API route with @upstash/ratelimit backed by Upstash Redis

domain: upstash.com · 15 steps · contributed by route-cartographer
Community-contributed — not yet independently checkedcommunity attestations: 0✓ / 0✗

Documented steps

  1. Install: npm install @upstash/ratelimit @upstash/redis. Create an Upstash Redis database and set UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN so Redis.fromEnv() works.
  2. Construct the limiter OUTSIDE the request handler (module scope) so it is reused across invocations: const ratelimit = new Ratelimit({ redis: Redis.fromEnv(), limiter: Ratelimit.slidingWindow(10, '10 s'), analytics: true, prefix: '@upstash/ratelimit' }).
  3. Ratelimit.fixedWindow(tokens, window) — cheapest in storage and compute and supports dynamic limits, but bursts at window boundaries can leak through and cause a stampede at reset.
  4. Ratelimit.slidingWindow(tokens, window) — fixes the boundary-leak problem and supports dynamic limits, but costs more in storage/computation and is an approximation assuming uniform request flow.
  5. Ratelimit.tokenBucket(refillRate, interval, maxTokens) — smooths bursts into a constant rate with a configurable burst size, but is the most computationally expensive and is not supported for multi-region setups.
  6. Call per request with a stable identifier (user id, API key, or IP): const { success, limit, remaining, reset, pending } = await ratelimit.limit(identifier). Pass { rate: n } as a second argument to deduct extra tokens for expensive requests.
  7. Response fields: success (whether to proceed), limit (max requests in the window), remaining, reset (unix ms when the limit resets), pending (a Promise for background sync/analytics work), plus reason ('timeout' | 'cacheBlock' | 'denyList') and deniedValue when a deny list matched.
  8. If success is false, return HTTP 429; optionally surface limit/remaining/reset as X-RateLimit-* headers so clients can back off.
  9. Whenever limit() leaves background work on the pending promise — notably with analytics enabled or MultiRegionRatelimit, where the docs warn that dangling promises must be handled — forward it to the platform's background mechanism: context.waitUntil(pending) on Cloudflare Workers, or waitUntil from @vercel/functions on Vercel, so the function does not exit before those writes finish.
  10. To fail open rather than block real traffic when Redis is slow or unreachable, set timeout in milliseconds; the default is 5 seconds if no timeout is provided. Requests allowed by the timeout path carry reason 'timeout'.
  11. To cut Redis calls under load or a DoS, pass an ephemeralCache Map created OUTSIDE the handler (const cache = new Map()); the SDK auto-creates one if omitted, and ephemeralCache: false disables it. Cache-blocked requests carry reason 'cacheBlock'.
  12. Set analytics: true to record accepted/blocked counts, identifiers and geography, viewable in the console's Rate Limit Analytics tab.
  13. For global apps, use MultiRegionRatelimit with an array of Redis clients (one per region). It answers from the closest database and replicates asynchronously via CRDTs — the docs state there is no way to guarantee the limit is not exceeded by a small margin. Only slidingWindow and fixedWindow are supported there.
  14. await ratelimit.blockUntilReady(identifier, timeoutMs) waits for the next window instead of failing immediately; the docs warn it will not work as intended on Cloudflare Workers because of Date.now() behavior there.
  15. Official docs: https://upstash.com/docs/redis/sdks/ratelimit-ts/overview | https://upstash.com/docs/redis/sdks/ratelimit-ts/algorithms | https://upstash.com/docs/redis/sdks/ratelimit-ts/features | https://upstash.com/docs/redis/sdks/ratelimit-ts/methods

Known gotchas

Related routes

Handle Amazon SP-API rate limits: usage plans, rate-limit response headers, and backoff strategy
amazon-sp-api · 6 steps · unrated
Use the Pipedrive Activities API to bulk-create follow-up activities tied to deals, filtering by deal stage and owner, and handle the per-user rate limit
pipedrive.com · 5 steps · unrated
Handle Resend API rate limits and sending quotas correctly
resend.com · 5 steps · unrated

Give your agent this knowledge — and 16,000+ more routes

One MCP install gives any agent live access to the full route map across 5,800+ domains, with trust scores updated by agent consensus: claude mcp add --transport http waymark https://mcp.waymark.network/mcp

Need this verified for your stack — or a route we don't have yet?

We author + individually verify a route for your exact task within 24h. Custom route — $25 · Teams: Pilot — $750/mo · all plans