Skip to content
OpenSmartRoute
Skillv1.0.0

upstash-ratelimit

Add rate limiting to API routes, middleware, and edge functions with @upstash/ratelimit: sliding window, fixed window, and token bucket backed by Upstash Redis.

by sickn33(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from sickn33/agentic-awesome-skills (skills/upstash-ratelimit/SKILL.md). Install upstream with npx skills add sickn33/agentic-awesome-skills --skill upstash-ratelimit. Copyright stays with the author.

Upstash Ratelimit

Overview

@upstash/ratelimit implements distributed rate limiting on top of Upstash Redis. Because state lives in Redis, every instance of a serverless function or edge worker shares the same counters, which an in-memory limiter cannot do. It ships three algorithms (fixed window, sliding window, token bucket), per-identifier keys, optional in-memory blocking of already-limited identifiers, and optional analytics.

When to Use This Skill

  • Use when the user needs to limit requests per IP, user, API key, or tenant across multiple serverless instances or regions.
  • Use when protecting login, signup, form, webhook, or LLM endpoints from abuse and returning 429 Too Many Requests.
  • Use when choosing between fixed window, sliding window, and token bucket.
  • Do not use for client-side retry/backoff against a third-party API's limits; see api-rate-limit-handler.
  • Do not use for a single long-running process with no shared state; an in-memory limiter is simpler there.

How It Works

Step 1: Install and configure

npm install @upstash/ratelimit @upstash/redis

Set UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN in the environment.

Step 2: Create the limiter once, outside the handler

import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

export const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, "10 s"), // 10 requests per 10 seconds
  prefix: "rl:api",
  analytics: true,
});

Constructing the limiter at module scope lets the built-in ephemeral cache short-circuit blocked identifiers without a Redis call.

Step 3: Call limit() with a stable identifier

const { success, limit, remaining, reset, pending } = await ratelimit.limit(userId);

success is false when the identifier is over its limit. reset is a Unix timestamp in milliseconds. pending is a promise for background work (analytics, multi-region sync); await it or pass it to waitUntil on edge runtimes so the function is not frozen before it completes.

Examples

Example 1: Next.js middleware returning 429

import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
import { NextResponse, type NextRequest } from "next/server";

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(20, "1 m"),
});

export async function middleware(request: NextRequest) {
  const ip = request.headers.get("x-forwarded-for") ?? "anonymous";
  const { success, limit, remaining, reset } = await ratelimit.limit(ip);

  if (!success) {
    return new NextResponse("Too Many Requests", {
      status: 429,
      headers: {
        "X-RateLimit-Limit": String(limit),
        "X-RateLimit-Remaining": String(remaining),
        "X-RateLimit-Reset": String(reset),
        "Retry-After": String(Math.ceil((reset - Date.now()) / 1000)),
      },
    });
  }
  return NextResponse.next();
}

export const config = { matcher: "/api/:path*" };

Example 2: Token bucket with per-plan limits

const limiters = {
  free: new Ratelimit({
    redis: Redis.fromEnv(),
    prefix: "rl:free",
    limiter: Ratelimit.tokenBucket(5, "10 s", 10), // refill 5 per 10 s, burst 10
  }),
  pro: new Ratelimit({
    redis: Redis.fromEnv(),
    prefix: "rl:pro",
    limiter: Ratelimit.tokenBucket(50, "10 s", 100),
  }),
};

const { success } = await limiters[plan].limit(apiKey);

Best Practices

  • ✅ Use a stable, low-cardinality identifier (user id, API key, tenant) where possible; fall back to IP only for anonymous traffic.
  • ✅ Set a distinct prefix per endpoint or plan so limits do not collide.
  • ✅ Return Retry-After and X-RateLimit-* headers with 429 responses.
  • ✅ Prefer slidingWindow for most APIs; use tokenBucket when short bursts are acceptable; use fixedWindow when the lowest Redis cost matters.
  • ❌ Don't construct a new Ratelimit inside the request handler.
  • ❌ Don't rely on pending completing on its own in edge runtimes.
  • ❌ Don't rate limit by x-forwarded-for without validating it is set by your proxy; clients can spoof it otherwise.

Limitations

  • Requires an Upstash Redis database; it does not work with other Redis servers or without network access.
  • Each limit() call is at least one HTTP round trip to Redis, so it adds latency to every request it guards.
  • Sliding window is an approximation that assumes an even spread of requests in the previous window; it is not an exact log.
  • MultiRegionRatelimit trades strict accuracy for lower latency and does not support the token bucket algorithm.
  • If Redis is unreachable, the default timeout (5 s) lets requests through (reason: "timeout"); this fails open, not closed.
  • This skill does not replace environment-specific validation, testing, or expert review.

Security & Safety Notes

  • Rate limiting is one layer of abuse protection, not authentication. Pair it with auth and input validation.
  • The Redis token grants full database access; keep it server-side.
  • Changing limits in production can lock out legitimate users. Confirm the numbers with the user before deploying stricter limits.

Common Pitfalls

  • Problem: Every request is allowed even after the limit. Solution: Each identifier must be the same string across requests; check that the identifier is not undefined or a fresh random value.
  • Problem: Analytics are empty on Vercel Edge or Cloudflare Workers. Solution: Pass pending to waitUntil (ctx.waitUntil(pending)) so the background request is not cancelled when the response is sent.

Related Skills

  • @upstash-redis - The client this package uses for storage.
  • @api-rate-limit-handler - Client-side backoff and retry when you are the one being rate limited.
  • @upstash-qstash - Queue and smooth traffic to downstream services instead of rejecting it.

Additional Resources

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/sickn33-agentic-awesome-skills-upstash-ratelimit/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

sickn33-agentic-awesome-skills-upstash-ratelimit.ocm.jsonjson
{
  "ocm": "1",
  "id": "sickn33-agentic-awesome-skills-upstash-ratelimit",
  "kind": "skill",
  "name": "upstash-ratelimit",
  "description": "Add rate limiting to API routes, middleware, and edge functions with @upstash/ratelimit: sliding window, fixed window, and token bucket backed by Upstash Redis.",
  "publisher": "sickn33",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding"
    ],
    "tags": [
      "skill-md",
      "upstash",
      "rate-limiting",
      "redis",
      "serverless",
      "edge",
      "middleware",
      "429",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Add rate limiting to API routes, middleware, and edge functions with @upstash/ratelimit: sliding window, fixed window, and token bucket backed by Upstash Redis."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/sickn33/agentic-awesome-skills",
      "path": "skills/upstash-ratelimit/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/sickn33/agentic-awesome-skills/blob/HEAD/skills/upstash-ratelimit/SKILL.md",
      "key": "sickn33/agentic-awesome-skills/skills/upstash-ratelimit/SKILL.md"
    }
  },
  "instructions": "# Upstash Ratelimit\n\n## Overview\n\n`@upstash/ratelimit` implements distributed rate limiting on top of Upstash\nRedis. Because state lives in Redis, every instance of a serverless function\nor edge worker shares the same counters, which an in-memory limiter cannot\ndo. It ships three algorithms (fixed window, sliding window, token bucket),\nper-identifier keys, optional in-memory blocking of already-limited\nidentifiers, and optional analytics.\n\n## When to Use This Skill\n\n- Use when the user needs to limit requests per IP, user, API key, or tenant\n  across multiple serverless instances or regions.\n-",
  "cost": {
    "context_tokens": 1575
  }
}

Fetch it by URL: GET /api/v1/registry/sickn33-agentic-awesome-skills-upstash-ratelimit/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.