site logo

Stacknatic

Stacknatic logo

We Care About Your Privacy

Stacknatic utilizes technologies, such as cookies, to enhance your browsing experience. By using this technology, you can be provided with a more personalized and seamless interaction with this website. By continuing, you agree with the Privacy Policy of Stacknatic.

Privacy Policy | Terms of Use
Home/blog/How to apply rate limit to Next.js App router

How to apply rate limit to Next.js App router

featured image for How to apply rate limit to Next.js App router

Published on: February 5, 2024 (Updated on: July 14, 2024)

Table of Contents

  • What is rate limit in API context?
  • Why use rate-limiting for your API?
  • What is Redis?How to install Redis

In this article, I am going to show you how to control access to an API resource in Next.js 13 and 14 using the App router. The technique I am going to demonstrate involves using Redis on your own server for rate limiting. This is a useful alternative to Vercel kv if your Next.js app is self-hosted. Similar posts available on this topic are based on the Next.js Page router, so I thought creating this post would be beneficial for those using the new Next.js app router.

To use Redis for rate-limiting in the Next.js App router, you need to have Redis installed on your server. You should probably use a VPS or similar hosting that grants you root access, as some shared hosting services do not offer Redis on their servers. If you're not familiar with Redis, don't worry; it's quite easy to install.

What is rate limit in API context?

Rate-limiting, sometimes referred to as throttling, can help prevent abuse, protect against denial-of-service (DoS) attacks, and ensure fair usage of server resources. It involves restricting the number of requests made to a server or API within a defined period. Rate-limiting sets thresholds on the frequency of requests, typically measured in requests per second (RPS) or requests per minute (RPM). When the limit is reached, further requests may be delayed, rejected, or handled differently based on the rate-limiting strategy in place.

Why use rate-limiting for your API?

Implementing rate-limiting for your API offers several benefits:

  • Prevent Abuse: Limiting requests discourages spamming, scraping, or unauthorized access.
  • Protect Server Resources: Controls incoming requests to prevent server overload.
  • Ensure Fair Usage: Treats all clients equally, preventing resource monopolization.
  • Mitigate DoS Attacks: Defends against flooding attacks, ensuring API availability.

Imagine you're using a third-party API like Spotify, and it grants you 200 requests per day. While your site visitors may use your resource moderately, a malicious bot could exhaust your API limit within seconds.

Creating your own API allows more generous API hits, but with third-party APIs, you may need to apply a rate limit. This is crucial, especially if you're charged per API call.

For self-hosted APIs, rate limiting or throttling might be built into your framework. For example, Django Rest Framework includes a throttle class for easy implementation.

When using a third-party API, applying a rate limit at the frontend is often the best choice. It prevents unnecessary trips to the backend, improving efficiency.

What is Redis?

Redis is like a Swiss Army knife for data storage. It can do it all: caching, acting as a database, and even handling streaming tasks. With support for different data structures like strings, lists, and sets, Redis is popular in real-time applications due to its speed, flexibility, and compatibility with various data types.

When you're setting rate limits in Next.js, you can use Redis to keep track of incoming requests and their sources in real-time.

How to install Redis

If you are using debian linux, you can install Redis with:

sudo apt install redis

On other linux distros, the command might vary slighly. You can read more about how to install Redis on your linux server here.

For macOs, you can install Redis with brew:

brew install redis

Next, you need to install a Redis client in Next.js. You can install it with:

npm install ioredis

In the root of your Next.js app or utilities folder (eg ‘/utilities/rateLimit.ts’), create a file called rateLimit.ts and add the following content:

import Redis from "ioredis";

type Limit = {
maxRequests: number;
remainingRequests: number;
exceeded: boolean;
};

export const rateLimit = async (
redis: Redis,
ip: string,
maxRequests: number,
duration: number
): Promise<Limit> => {
const key = `api_throttle:${ip}`;
let requestCount = await redis.get(key);

// Parse current count, defaulting to 0
let madeRequests = parseInt(requestCount || "0", 10) || 0;

if (madeRequests >= maxRequests) {
return { maxRequests, remainingRequests: 0, exceeded: true }; // No remaining requests
}

// Increment count and set expiration time
await redis.incr(key);
await redis.expire(key, duration);

// Calculate remaining count
let remainingRequests = maxRequests - madeRequests;

return { maxRequests, remainingRequests, exceeded: false };
};

Create environment variables for Redis in your dotenv (.env) file with the following:

Redis_HOST=localhost
REDIS_PASSWORD= # provide your redis password here if you are using a password for redis otherwise leave blank
Redis_PORT=6379 # this is the default port for Redis

Next, open your Next.js API route. In the Next.js app router, this would be at, for example, '/app/api/nameofapi/route.ts/'.

Note that ‘nameofapi’ is a placeholder and should be replaced with the name of your api, eg ‘chat-api’.

Add the following to your imports at the top of the file:

import { rateLimit } from '@/utilities/rateLimit';
import Redis, { RedisOptions } from 'ioRedis';

Add this also:

const options: RedisOptions = {
host: process.env.REDIS_HOST!,
password: process.env.REDIS_PASSWORD!,
port: parseInt(process.env.REDIS_PORT!, 10),
};

In your Next.js App router API function, the part that begins with ‘export async function POST(req: NextRequest)’, add the following:


const redis = new Redis(options); 

const limit = await rateLimit(
redis,
req.ip ?? '127.0.0.1', 
maxRequests, 
60, // 1 minute
);



NextResponse.json({"X-RateLimit-Limit": limit.maxRequests, "X-RateLimit-Remaining": limit.remainingRequests})
if (!result.success) {


return NextResponse.json({ error: "Rate limit exceeded" }, { status: 429 });

That's it, access to your API should now be subject to the limit that you have applied. Happy rate-limiting!

See more posts in Websites
Author:author's avatarMichael Akerele