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);
- Use Sliding Window Algorithm for a smoother (but more expensive) rate limiting experience.
const ratelimit = new Ratelimit({
redis: redis,
limiter: Ratelimit.slidingWindow(10, "10 s"),
});
const ratelimit = new Ratelimit({
redis: redis,
limiter: Ratelimit.slidingWindow(10, "10 s"),
});
- Use Token Bucket Algorithm to tolerate some amount of spike.
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.