← Back to blog
··12 min read

Arcjet vs Upstash Ratelimit vs Unkey 2026: Best Rate Limiting for Next.js

ArcjetUpstashUnkeyRate LimitingAPISecurityNext.jsServerless
Arcjet vs Upstash Ratelimit vs Unkey 2026: Best Rate Limiting for Next.js
Rows of servers in a data center representing API rate limiting infrastructure

Rows of servers in a data center representing API rate limiting infrastructure

The first time a scraper, a runaway script, or a credential-stuffing bot hits your Next.js API, you learn the same lesson everyone does: an unprotected endpoint is a liability. Rate limiting is no longer a "nice to have" you bolt on before launch — it is table stakes for any route that signs people up, sends email, calls a paid LLM, or touches a database.

In 2026 three names dominate the "how do I rate limit my Next.js API" conversation: Arcjet, Upstash Ratelimit, and Unkey. They solve overlapping problems from very different angles. One is a security SDK. One is a Redis-backed library. One is an API-key platform. This guide breaks down how each actually works, what it costs, and the clear situations where one beats the other two.

The 30-second answer

  • Upstash Ratelimit — you already use (or are happy to add) Upstash Redis and you want a battle-tested library with fixed-window, sliding-window, and token-bucket algorithms that you control completely.
  • Arcjet — you want rate limiting plus bot detection, a WAF, and email validation in a single SDK that makes its decision right next to your function. The all-in-one abuse-protection choice.
  • Unkey — you are shipping an API as a product and need to issue keys, meter usage, and attach a rate limit to each key, enforced globally at the edge with zero infrastructure of your own.
  • If you remember nothing else: Upstash for control, Arcjet for all-in-one protection, Unkey for API-key products.

    Why in-memory rate limiting fails on serverless

    Before comparing the three, it helps to understand why you need any of them. The naive approach is a Map in memory that counts requests per IP. It works perfectly on your laptop and falls apart in production.

    Next.js on Vercel, or any serverless platform, runs many instances of your function in parallel and spins them up and down on demand. Each instance has its own memory. A user making ten requests might hit ten different instances, each seeing "one request" and letting them all through. Your limit of ten per minute silently becomes ten per minute *per instance*.

    Fixing this needs shared state that every instance reads from — a centralized counter. That is the problem Upstash, Arcjet, and Unkey each solve in their own way.

    How each one actually works

    Upstash Ratelimit

    Upstash Ratelimit is an open-source SDK that runs against an Upstash Redis database over a REST API, which means it works from edge and serverless runtimes without a persistent TCP connection. You pick an algorithm and a window, and the library stores the counters in your Redis.

    It supports fixed window (simple, cheap, allows bursts at window edges), sliding window (smoother, the common default), and token bucket (lets you model burst capacity plus a steady refill rate). You can define multiple limits for different plans and use ephemeral in-memory caching to short-circuit obviously-blocked clients and save Redis calls. Because you own the Redis instance and the config, you have the most control of the three — and the most to wire up.

    Arcjet

    Arcjet is a security SDK first and a rate limiter second. You install one package and compose rules: rate limiting (fixed window, sliding window, or token bucket), bot detection, a Shield WAF that catches common attacks like SQL injection, email validation that rejects disposable or invalid addresses, and more recent additions like PII detection. The decision runs close to your code, and the heavy analysis happens on Arcjet's side so your function stays light.

    The appeal is consolidation: instead of gluing together a rate limiter, a bot filter, and an email validator from three vendors, you express all of it as rules in one place. It works across Next.js, Nuxt, SvelteKit, Astro, Express, Fastify, Hono, NestJS, Remix, and more. The trade-off is that you are adopting a whole protection layer, not just a counter.

    Unkey

    Unkey is built for a specific shape of product: you have an API and you sell or gate access to it. It issues and verifies API keys, meters usage, and — the part relevant here — does globally distributed rate limiting at the edge with no Redis for you to run.

    It offers two modes. Standalone limits let you call limit() against any identifier (a user ID, an IP, a route) just like a classic rate limiter. Key-attached limits are set per API key and enforced automatically during key verification, so every customer's key carries its own ceiling. For an API product, that second mode is the killer feature — your rate limits live with your keys instead of being reimplemented in app code.

    Side-by-side comparison

    FactorUpstash RatelimitArcjetUnkey
    Primary jobRate limiting libraryFull abuse-protection SDKAPI-key management + limits
    Backing storeYour Upstash RedisManaged by ArcjetManaged by Unkey
    Infra to runUpstash Redis databaseNoneNone
    AlgorithmsFixed, sliding, token bucketFixed, sliding, token bucketSliding window
    Bot detectionNoYesNo
    WAF / ShieldNoYesNo
    Email validationNoYesNo
    Per-API-key limitsManualManualNative
    Edge-readyYes (REST)YesYes
    Best framework fitAnyNext.js, many moreAny API product
    Pricing shapeFree SDK + Redis usageUsage-based per requestFree tier + usage

    Pricing figures move constantly; always confirm the current numbers on each vendor's pricing page before you commit. The *shape* of the models rarely changes: Upstash bills you for Redis commands, Arcjet bills per million requests analysed, and Unkey bills per verification and rate-limit check above a free allotment.

    Code: the same guard, three ways

    All three slot into a Next.js route handler. Here is the same "limit this endpoint" guard in each.

    ts
    // Upstash Ratelimit — sliding window, backed by your Upstash Redis
    import { Ratelimit } from "@upstash/ratelimit";
    import { Redis } from "@upstash/redis";
    
    const ratelimit = new Ratelimit({
      redis: Redis.fromEnv(),
      limiter: Ratelimit.slidingWindow(10, "60 s"),
      analytics: true,
    });
    
    export async function POST(req: Request) {
      const ip = req.headers.get("x-forwarded-for") ?? "anonymous";
      const { success, limit, remaining } = await ratelimit.limit(ip);
      if (!success) {
        return new Response("Too many requests", {
          status: 429,
          headers: { "X-RateLimit-Remaining": String(remaining) },
        });
      }
      return Response.json({ ok: true });
    }
    ts
    // Arcjet — rate limit + bot detection in one rule set
    import arcjet, { tokenBucket, detectBot } from "@arcjet/next";
    
    const aj = arcjet({
      key: process.env.ARCJET_KEY!,
      rules: [
        tokenBucket({ mode: "LIVE", refillRate: 5, interval: 10, capacity: 10 }),
        detectBot({ mode: "LIVE", allow: ["CATEGORY:SEARCH_ENGINE"] }),
      ],
    });
    
    export async function POST(req: Request) {
      const decision = await aj.protect(req, { requested: 1 });
      if (decision.isDenied()) {
        return new Response("Forbidden", { status: 403 });
      }
      return Response.json({ ok: true });
    }
    ts
    // Unkey — standalone edge rate limit, no Redis to manage
    import { Ratelimit } from "@unkey/ratelimit";
    
    const unkey = new Ratelimit({
      rootKey: process.env.UNKEY_ROOT_KEY!,
      namespace: "api",
      limit: 10,
      duration: "60s",
    });
    
    export async function POST(req: Request) {
      const ip = req.headers.get("x-forwarded-for") ?? "anonymous";
      const { success } = await unkey.limit(ip);
      if (!success) return new Response("Too many requests", { status: 429 });
      return Response.json({ ok: true });
    }

    Notice the shape is nearly identical — call a guard, check success, return a 429 or 403. What differs is everything *behind* that call: Upstash reads your Redis, Arcjet also runs bot analysis, and Unkey resolves against its global edge network. (APIs evolve; check each SDK's current docs for exact method names before copying.)

    Global network of connected nodes representing edge-distributed rate limiting

    Global network of connected nodes representing edge-distributed rate limiting

    When to choose each one

    Choose Upstash Ratelimit if…

  • You already run Upstash Redis for caching, queues, or sessions — adding rate limiting is nearly free and reuses infrastructure you know.
  • You want to control the algorithm and the data: tune the window, inspect the counters, run your own analytics.
  • You are comfortable managing one more dependency in exchange for maximum flexibility.
  • It pairs naturally with the rest of the Upstash stack — see how Upstash Redis itself stacks up in our Upstash vs Redis Cloud vs Dragonfly comparison.

    Choose Arcjet if…

  • You want one SDK that handles rate limiting, bots, a WAF, and email validation instead of stitching three vendors together.
  • You are protecting signup, login, contact, and payment routes where abuse comes from bots as much as from raw request volume.
  • You value expressing security as composable rules living next to your code.
  • If bot traffic is your real problem, also weigh a dedicated challenge layer — compare the options in Turnstile vs reCAPTCHA vs hCaptcha, and lock down the auth routes themselves with a solid stack from Clerk vs Auth.js vs Better Auth.

    Choose Unkey if…

  • You are building an API product: developers get keys, and each key needs its own limit and usage metering.
  • You want rate limiting enforced at the edge with zero infrastructure of your own.
  • You want limits to travel *with the key* rather than be reimplemented in every route.
  • Unkey fits neatly in front of an API built with something like Hono, and the choice of REST vs GraphQL vs tRPC does not change which protection layer you reach for.

    The honest trade-offs

    No tool is free of sharp edges.

  • Upstash means managing Redis. It is the most flexible option but also the one where you own a database, its limits, and its bill. A misconfigured window or a hot key can surprise you.
  • Arcjet is a broad dependency. You are adopting a protection platform, not a tiny library. That is the point if you want consolidation, and overkill if all you need is a single counter.
  • Unkey is opinionated toward API products. If you are not issuing keys, its standalone rate limiting works, but you are using a slice of a platform built for a different job.
  • Every managed service adds a network hop. Arcjet and Unkey resolve decisions remotely; they are engineered to be fast and edge-close, but a rate-limit check is still a call. Fail *open* or *closed* deliberately for your use case.
  • Where the request runs matters

    As with databases, latency is about *distance*. A rate-limit check that adds 150 ms because it crosses a continent will hurt more than the abuse it prevents. All three are built for serverless and edge runtimes, but confirm your limiter resolves near your compute. If you are still choosing that compute layer, our Cloudflare Workers vs AWS Lambda vs Vercel Functions guide covers the trade-offs that decide where your guard actually runs.

    Bottom line

    There is no single winner, because these three target different problems:

  • Reach for Upstash Ratelimit when you want a flexible, well-proven library you control, and you already live in the Upstash ecosystem.
  • Reach for Arcjet when you want rate limiting as one part of a complete abuse-protection layer — bots, WAF, and email validation included.
  • Reach for Unkey when your product *is* an API and limits belong with the keys you issue.
  • Decide based on whether you need more than counting (then Arcjet) and whether you are shipping an API product (then Unkey); otherwise Upstash Ratelimit is the dependable default.

    ---

    Building a Next.js SaaS and want the API layer handled for you? Browse production-ready starters on CodeCudos — including Next.js auth templates and Stripe subscription SaaS boilerplates that wire auth, billing, and protected routes together so you can ship in a weekend.

    Frequently asked questions

    What is the difference between Arcjet, Upstash Ratelimit, and Unkey?▾

    Upstash Ratelimit is an SDK you run against your own Upstash Redis database, giving you fixed-window, sliding-window, and token-bucket algorithms with full control. Arcjet is a broader security SDK where rate limiting is one feature alongside bot detection, a Shield WAF, email validation, and PII detection, all decided close to your function. Unkey is an API-key management platform whose rate limiting is globally distributed at the edge with no Redis for you to manage, and it can attach limits directly to each API key.

    Which is cheapest for a side project or MVP?▾

    All three have free tiers that comfortably cover an MVP. Upstash Ratelimit itself is free — you only pay for the underlying Upstash Redis, which has a generous free command allowance. Unkey offers a free tier with a monthly allotment of verifications and rate-limit checks. Arcjet's free tier covers low-volume apps and its paid plans are usage-based per million requests. At tiny scale the differences are negligible; pricing matters once you are doing millions of requests a month, so confirm current numbers on each vendor's pricing page.

    Do I need Redis to rate limit a Next.js app?▾

    Not necessarily. Upstash Ratelimit needs an Upstash Redis database as its backing store. Arcjet and Unkey are both managed services that keep the distributed state for you, so you add no Redis of your own. An in-memory limiter needs no Redis either, but it breaks the moment you run more than one serverless instance because each instance counts separately — which is exactly why teams reach for one of these three.

    Which one also stops bots and abuse, not just rate limiting?▾

    Arcjet is the only one of the three built as a full abuse-protection layer: alongside rate limiting it ships bot detection, a Shield WAF for common attacks, and email validation to block disposable signups. Upstash Ratelimit and Unkey focus on counting and limiting requests. If you need bot filtering as well, either use Arcjet or pair a rate limiter with a separate bot/CAPTCHA layer like the ones compared in our Turnstile vs reCAPTCHA vs hCaptcha guide.

    Related guides

    Browse Quality-Scored Code

    Every listing on CodeCudos is analyzed for code quality, security, and documentation. Find production-ready components, templates, and apps — or sell your own code and keep 90%.

    Browse Marketplace →