DEV Community

James Perkins
James Perkins

Posted on • Originally published at jamesperkins.dev on

Rate limiting in Next.js in under 10 minutes

Rate limiting is an important feature that you need in production applications. It may sound scary, but it's actually fairly easy to implement API rate limiting in today's world. In this blog post, we'll walk through the process of implementing rate limiting using Upstash and Redis.

In this example we are using my t3-clerk-minimal app that you can find here. Make sure you have your Clerk keys in your application before starting.

What is Upstash?

upstash-home

Upstash is a serverless data stack that can be served to you on the edge using Redis or Qstash. Most people prefer Redis, and it has a really good free tier. We're going to use Upstash to implement rate limiting because they have a rate limit package that makes it dead simple to implement anywhere that you're using APIs.

First, you need to sign up for an account. Once you've done that, you'll need to click on your console and create a new database. Give it a name, and set the region to the correct region for your area (e.g. US East One or US West).

You can enable TLS if you want. Go ahead and create your Redis for Upstash.

Setting up the ENV

Now that your Redis instance has been created, you'll need to set up the ENV with your Redis REST URL and token. You can copy these information from the Upstash console.

env

From here, go to your IDE (e.g. Visual Studio Code) and add a .env file. You should already have your Upstash URLs and token in there. Close the .env file once you've pasted your Redis instance details.

Using Clerk for User Authentication

If you haven't used Clerk before, it's a user authentication and management system for the modern web, supporting frameworks like Next.js, Remix, and Gatsby. In this example, we'll be using Clerk for user authentication and protected routes.

To implement rate limiting, we need an identifier for the user (e.g. user ID, IP address) to determine if the same user is making multiple requests. We'll use the user ID from Clerk for this purpose.

Creating the Rate Limiter

First, we need to install two packages, upstash-rate-limit and upstash-redis. You can do so by running:

npm install @upstash/ratelimit @upstash/redis

Enter fullscreen mode Exit fullscreen mode

Next, import both packages in your example router and initialize the rate limiter:

import RateLimit from '@upstash/ratelimit';
import Redis from '@upstash/redis';

const rateLimiter = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(2, "3 s")
});

Enter fullscreen mode Exit fullscreen mode

This example sets a rate limit of 2 requests per 3 seconds. You can adjust the values as needed.

Implementing the Rate Limiter in a Protected Route

Now, we will implement the rate limiter in a protected route. First, create your route (in this example, we'll call it expensive). Inside the route, use the rate limiter with the user ID from Clerk:

import { TrpcError } from '@trpc/server';

// other routes
 expensive: protectedProcedure.query(async ({ ctx }) => {
    const { success } = await rateLimiter.limit(ctx.auth.userId);
    if (!success) {
      throw new TRPCError({ code: "TOO_MANY_REQUESTS" })
    }
    return "expensive"
  })

Enter fullscreen mode Exit fullscreen mode

This code checks whether the rate limit has been exceeded; if it has, a "Too Many Requests" error is thrown.

Testing the Rate Limiter

Now that the rate limiter has been implemented in your application, you can test your protected route to ensure the rate limiting is working as intended. In this example, we will test the rate limiter using a "click here to protected procedure" button on a web page.

Run your application with npm run dev, and navigate to your localhost URL. Click the button, sign in using your preferred authentication method, and you should be redirected to the protected page. Open your browser console and refresh the page - you should encounter a "Too Many Requests" error if you refresh too often.

If you wait a few seconds and refresh again, the error should be gone, indicating that the rate limiting is working as intended.

Conclusion

In this blog post, we've demonstrated how to implement rate limiting using Upstash and Redis, as well as integrating the rate limiter with Clerk for user authentication. Implementing rate limiting is an important aspect of maintaining a secure and stable production application, and this guide should help you get started in adding it to your own projects.

If you found this guide helpful, please consider subscribing to my Youtube channel or the newsletter for more tips and tutorials for web development. Happy coding!

Top comments (0)