Published on

How to Implement Rate Limiting in Next.js

Authors

Rate limiting helps to protect your API endpoint from abuse. This is useful especially if you're providing a public API endpoint.

With the help of rate limiting, we can limit the number of requests for our API endpoints within a given timeframe.

When we get more requests than that, then it is blocked with 429 Too Many Requests error.

Here is how to implement that in Next.js

Dependencies

# Create a new Next.js project
npx create-next-app@latest

We'll be using Vercel KV and Upstash's rate limiting package for handling rate limiting.

npm i @vercel/kv @upstash/ratelimit

And make sure to setup and configure the Vercel KV-related environmental properties

Example Snippet

// example-next-app/src/app/api/hello-world/route.js
// reference: https://github.com/steven-tey/novel/blob/main/app/api/generate/route.ts
import { kv } from "@vercel/kv";
import { Ratelimit } from "@upstash/ratelimit";

export async function GET(req) {
    if (
        process.env.NODE_ENV != "development" &&
        process.env.KV_REST_API_URL &&
        process.env.KV_REST_API_TOKEN
    ) {
        // https://nesin.io/blog/nextjs-getserversideprops-ip-address
        const ip = req.headers.get("x-forwarded-for");
        const NUMBER_OF_REQUESTS = 10;
        const DURATION = "1 d";
        const ratelimit = new Ratelimit({
            redis: kv,
            limiter: Ratelimit.slidingWindow(NUMBER_OF_REQUESTS, DURATION),
        });

        const { success, limit, reset, remaining } = await ratelimit.limit(
            `your_app_ratelimit_${ip}`,
        );

        if (!success) {
            return new Response("You have reached your request limit for the day.", {
                status: 429,
                headers: {
                    "X-RateLimit-Limit": limit.toString(),
                    "X-RateLimit-Remaining": remaining.toString(),
                    "X-RateLimit-Reset": reset.toString(),
                },
            });
        }
    }

    return new Response("It works", {
        status: 200,
    });
}

Happy rate limiting!