Skip to content

Rate Limiting

Protect your API routes and authentication endpoints from abuse using Upstash Redis.

Setup (Applies to Both Use Cases)

  1. Sign up on Upstash and create a new Redis database
  2. Add to .env.local:
    bash
    UPSTASH_REDIS_REST_URL=https://your-db.upstash.io
    UPSTASH_REDIS_REST_TOKEN=your_token
  3. Install packages:
    bash
    npm install @upstash/redis @upstash/ratelimit

Rate Limiting API Routes

Create /middleware.js in your project root:

javascript
// /middleware.js
import { NextResponse } from "next/server";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL,
  token: process.env.UPSTASH_REDIS_REST_TOKEN,
});

const ratelimit = new Ratelimit({
  redis: redis,
  limiter: Ratelimit.slidingWindow(5, "60 s"),
});

export default async function middleware(request) {
  const ip = request.ip ?? "127.0.0.1";
  const { success } = await ratelimit.limit(ip);

  return success
    ? NextResponse.next()
    : NextResponse.redirect(new URL("/blocked", request.url));
}

export const config = {
  matcher: ["/api/one", "/api/two"],  // Replace with your actual API routes
};

Algorithm: sliding window — 5 requests per 60 seconds per IP.

Create /app/blocked/page.js — the page shown when a user hits the rate limit.

Same Upstash setup. Change the matcher to the NextAuth email sign-in route:

javascript
export const config = {
  matcher: ["/api/auth/signin/email"],
};

This prevents abuse of the magic link email endpoint.

Mailgun Sending Limit

If using Mailgun (instead of Resend), set a Custom Message Limit in your Mailgun account settings. Recommended: 5,000 messages/month. This caps exposure if your sending endpoint is abused.

See Also