Rate Limiting in Next.js: Protecting Your API from Excessive Requests

Why Use Redis for Rate Limiting?

Redis is an ideal choice for rate limiting due to its high performance, scalability, and ease of use. Its in-memory data storage allows for fast data retrieval and manipulation, making it perfect for tracking and managing request rates. Additionally, Redis provides a range of useful features, such as atomic operations and data structures, that make implementing rate limiting algorithms a breeze.

Setting Up Redis

Before we dive into implementing rate limiting, let’s first set up Redis on our system. We’ll cover installation methods for macOS, Linux, and Docker.

macOS (Homebrew)


/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install redis
brew services start redis

Linux (Package Manager)


sudo apt-get install redis-server  # Debian/Ubuntu
sudo yum install redis  # CentOS/Red Hat
sudo dnf install redis  # Fedora

sudo service redis-server start  # Debian/Ubuntu
sudo systemctl start redis  # CentOS/Red Hat
sudo systemctl start redis  # Fedora

Docker


docker pull redis
docker run -d -p 6379:6379 --name redis redis

Installing the Redis Client

Next, we’ll install the Redis client library for Node.js, ioredis. Run the following command:


npm install ioredis

Selecting a Rate Limiting Algorithm

For this example, we’ll use the token bucket algorithm, a simple and effective method for rate limiting. This algorithm works by assigning each client a “token” that expires after a certain amount of time.

Creating the Rate Limiting Method

Now that we’ve selected our algorithm, let’s create a method to handle request limits for every user who calls our API. We’ll designate the user’s IP address to mark each unique request:


import Redis from 'ioredis';

const redis = new Redis();

const rateLimit = async (req, res, next) => {
  const ip = req.ip;
  const limit = 10; // requests per minute
  const expire = 60; // seconds

  const current = await redis.get(ip);
  if (current >= limit) {
    res.status(429).send('Too many requests');
    return;
  }

  await redis.incr(ip);
  await redis.expire(ip, expire);

  next();
};

export default rateLimit;

Setting the Rate Limit on the API

To implement the rate limiter on our API, we’ll create a new file, pages/api/redis-limit.ts, in the API folder:


import { NextApiRequest, NextApiResponse } from 'next';
import rateLimit from '../../lib/rateLimit';

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
  await rateLimit(req, res);

  // API logic here
};

export default handler;

Testing the Rate Limiter

To test our rate limiter, let’s create a simple Bash script to simulate requests:


#!/bin/bash

for i in {1..20}; do
  curl -X GET http://localhost:3000/api/redis-limit
done

Run the script and observe the output. The rate limiter should block requests after the limit is reached.

Serverless Redis Alternatives

If you prefer a serverless approach, consider the following Redis alternatives:

By implementing rate limiting with Redis in your Next.js application, you’ll protect your API from excessive requests and ensure a better experience for your users.

Leave a Reply