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
Setup Upstash database on the Upstash console. Once you’ve signed up or logged in, you should see this screen:
Click on “Create database“ and fill in the details like below, choose the free plan for now, and create your database:
You should’ve been redirected to your database’s screen (it’s a Redis database, by the way).
Hover over your endpoint to see the following copy buttons:
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
Install Upstash dependencies:
npm install @upstash/ratelimit @upstash/redis
in your Next.js project.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(' ', '')}`, }); }
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
// ...
}
- 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:
Instagram: iam.charan.dev
X/Twitter: @CharanMNX
LinkedIn: Charan Manikanta Nalla
GitHub: CharanMN7
YouTube: Charan
Website: charan.dev
Happy Coding or Vibe Coding!
Subscribe to my newsletter
Read articles from Charan Manikanta Nalla directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Charan Manikanta Nalla
Charan Manikanta Nalla
I'm a software engineer and freelance full-stack developer. Need a website/app for your business? Hit me up on one of my socials, and let's talk!