·2 min read

Rate Limiting Next.js API Routes using Upstash Redis

Noah FischerNoah FischerDevRel @Upstash

In this article, we will show how to rate limit your Next.js API routes using the Upstash Rate limit SDK

Database Setup

Create a Redis database using Upstash Console or Upstash CLI. Copy the UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN for the next steps.

Project Setup

We will create a Next.js application and deploy to Vercel.

npx create-next-app@latest
npx create-next-app@latest

Install @upstash/ratelimit:

npm install @upstash/ratelimit @upstash/redis
npm install @upstash/ratelimit @upstash/redis

The Code

Update your pages/api/hello.js as below and replace UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN.

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


const redis = new Redis({
  url: 'UPSTASH_REDIS_REST_URL',
  token: 'UPSTASH_REDIS_REST_TOKEN',
})

// Create a new ratelimiter, that allows 5 requests per 5 seconds
const ratelimit = new Ratelimit({
  redis: redis,
  limiter: Ratelimit.fixedWindow(5, "5 s"),
});

export default async function handler(req, res) {
// Use a constant string to limit all requests with a single ratelimit
// Or use a userID, apiKey or ip address for individual limits.
  const identifier = "api";
  const result = await ratelimit.limit(identifier);
  res.setHeader('X-RateLimit-Limit', result.limit)
  res.setHeader('X-RateLimit-Remaining', result.remaining)

  if (!result.success) {
    res.status(200).json({message: 'The request has been rate limited.', rateLimitState: result})
    return
  }

  res.status(200).json({name: 'John Doe', rateLimitState: result})
}
import {Ratelimit} from "@upstash/ratelimit";
import {Redis} from "@upstash/redis";


const redis = new Redis({
  url: 'UPSTASH_REDIS_REST_URL',
  token: 'UPSTASH_REDIS_REST_TOKEN',
})

// Create a new ratelimiter, that allows 5 requests per 5 seconds
const ratelimit = new Ratelimit({
  redis: redis,
  limiter: Ratelimit.fixedWindow(5, "5 s"),
});

export default async function handler(req, res) {
// Use a constant string to limit all requests with a single ratelimit
// Or use a userID, apiKey or ip address for individual limits.
  const identifier = "api";
  const result = await ratelimit.limit(identifier);
  res.setHeader('X-RateLimit-Limit', result.limit)
  res.setHeader('X-RateLimit-Remaining', result.remaining)

  if (!result.success) {
    res.status(200).json({message: 'The request has been rate limited.', rateLimitState: result})
    return
  }

  res.status(200).json({name: 'John Doe', rateLimitState: result})
}

Here, we allow 5 requests per 5 seconds.

Run

Run the app with npm run dev. Refresh the browser more than 5 times and you will see the rate limiting in action.

{"message":"The request has been rate limited.","rateLimitState":{"success":false,"limit":5,"remaining":-1,"reset":1654546770000,"pending":{}}}
{"message":"The request has been rate limited.","rateLimitState":{"success":false,"limit":5,"remaining":-1,"reset":1654546770000,"pending":{}}}

Possible Enhancements

  • Use your user's id or IP address as identifier to limit the usage per user.
const identifier = getClientIp(req);
const result = await ratelimit.limit(identifier);
const identifier = getClientIp(req);
const result = await ratelimit.limit(identifier);
const ratelimit = new Ratelimit({
  redis: redis,
  limiter: Ratelimit.slidingWindow(10, "10 s"),
});
const ratelimit = new Ratelimit({
  redis: redis,
  limiter: Ratelimit.slidingWindow(10, "10 s"),
});
const ratelimit = new Ratelimit({
  redis: redis,
  limiter: Ratelimit.tokenBucket(5, "10 s", 10),
});
const ratelimit = new Ratelimit({
  redis: redis,
  limiter: Ratelimit.tokenBucket(5, "10 s", 10),
});
  • Use multiple Redis in different regions if your Next.js application is deployed to different regions. This will help you to minimize latency for different locations.

  • Keep and read your Upstash Redis credentials from environment variables or secret store.