How to rate limit your Next.js APIs using Upstash

How to rate limit your Next.js APIs using Upstash

Why Rate Limit your APIs?

Rate limiting APIs is important to prevent abuse or unexpected usage on your APIs.

For example, say you have a public waitlist form to collect emails of your potential users. Here, your API that handles your waitlist form submissions is probably unprotected because you want anyone to be able to sign up in your form without any restrictions or need for authentication.

But, there is chance that your form can be spammed with random/unwanted emails with the help of bots to exhaust your server limits or mess up your database with random emails.

If your API is rate-limited to, say, 5 emails per IP address per 10 minutes, all other submission from that IP address (the user or the bot) are rejected, hence saving you from what is possibly a brute-force attack.

Here’s how to rate limit a Next.js API using Upstash

  1. Setup Upstash database on the Upstash console. Once you’ve signed up or logged in, you should see this screen:

    Screenshot of a web page titled "Redis" with options for creating a Redis database. It shows sections for commands, average storage, and cost, all displaying zero. A green button labeled "Create database" is in the center. The page header includes navigation options and user profile icons.

  2. Click on “Create database“ and fill in the details like below, choose the free plan for now, and create your database:

    A screenshot of a Redis setup interface displaying a form to create a database. Fields include Name, Primary Region, and optional Read Regions. The region selected is "N. California, USA." There's a toggle for "Eviction" and a notice to add a payment method for paid plans. Buttons for "Cancel" and "Next" are at the bottom.

    Screenshot of a Redis database creation page showing the selection of a free plan for "N. California, USA," with features like Persistence, REST API, TLS, and Global. There's a note to add a payment method for paid plans and buttons to go back or create.

  3. You should’ve been redirected to your database’s screen (it’s a Redis database, by the way).

    Screenshot of a Redis management dashboard showing an endpoint, commands, bandwidth, storage, and cost details. It includes options for connecting using various programming languages like JavaScript and Python.

  4. Hover over your endpoint to see the following copy buttons:

    Screenshot of a Redis database interface on Upstash. It shows details like the number of commands, bandwidth, storage, cost, and endpoint information. The connect options include different programming languages such as JavaScript, Python, and PHP.

  5. Put the following environment variables in the .env.local:

    • Copy the “HTTPS” button’s content into the UPSTASH_REDIS_REST_URL environment variable.

    • Copy the “TOKEN” button’s content into the UPSTASH_REDIS_REST_TOKEN environment variable.

    • Your environment variables should include the following (with the real values):

    UPSTASH_REDIS_REST_URL=xxxxxxxxx
    UPSTASH_REDIS_REST_TOKEN=xxxxxxxxx
  1. Install Upstash dependencies: npm install @upstash/ratelimit @upstash/redis in your Next.js project.

  2. Add the following to lib/ratelimit.ts

     import { Ratelimit } from '@upstash/ratelimit';
     import { Redis } from '@upstash/redis';
    
     type Unit = 'ms' | 's' | 'm' | 'h' | 'd';
     type Duration = `${number} ${Unit}` | `${number}${Unit}`;
    
     // A function to create a ratelimiter instance with a given configuration
     export function createRateLimiter(requests: number, duration: Duration) {
       // During development, we don't want to rate-limit.
       if (process.env.NODE_ENV === 'development') {
         return {
           limit: () => {
             return {
               success: true,
               pending: Promise.resolve(),
               limit: requests,
               remaining: requests,
               reset: Date.now() + 1000,
             };
           },
         };
       }
    
       return new Ratelimit({
         redis: Redis.fromEnv(),
         limiter: Ratelimit.slidingWindow(requests, duration),
         analytics: true,
         // Create a unique prefix for each ratelimiter to avoid collisions
         prefix: `@clndr/ratelimit/${requests}-requests/${duration.replace(' ', '')}`,
       });
     }
    
  3. Add this to the Next.js API that you want to rate limit (route.ts)

    // Your imports
    // ...
    import { createRateLimiter } from '@/lib/ratelimit';

    const ratelimit = createRateLimiter(5, '600 s');

    export async function POST(request: NextRequest) {
      const ip = (request.headers.get('x-forwarded-for') ?? '127.0.0.1').split(',')[0];
      const { success, limit, remaining, reset } = await ratelimit.limit(ip);

      if (!success) {
        return NextResponse.json(
          { error: 'Too many requests. Please try again later.' },
          {
            status: 429,
            headers: {
              'X-RateLimit-Limit': limit.toString(),
              'X-RateLimit-Remaining': remaining.toString(),
              'X-RateLimit-Reset': reset.toString(),
            },
          },
        );
      }
      // Your API code goes here
      // ...
     }
  1. Test, Deploy, and Launch!

Here’s how to use this with AI tool(s) like Cursor

After you create the Upstash database and add the environment variables to your .env.local Write a prompt saying:

“Implement a rate-limiting for my {your API name} API using the instructions and the code, as is, in this blog post. I’ve already setup the Upstash database and added the necessary environment variables to .env.local. Also, do verify if the rate-limiting setup already exists in the codebase. Only add the rate-limiting function code if it doesn’t already exist:“

And, paste this post’s link in an code editor like Cursor and let it handle the coding for you!

P.S.

And… that’s it! Hope this helps!

Do you need a website or an app for your business?
You can reach out to me at @CharanMNX on X/Twitter or email me at charan@devsforfun.com

Here are my other socials if you wanna talk:

Happy Coding or Vibe Coding!