Skip to main content

Next.js

Step-by-step Next.js rate limiting tutorial with @unkey/ratelimit. Throttle API routes and return 429 responses without provisioning Redis.
2 min read

What you'll build#

A Next.js API route that limits each user to a set number of requests per time window. Excess requests get rejected with a 429.

Time to complete: ~5 minutes

Prerequisites#

Create a Next.js app#

Skip if you have an existing project.

Install the SDK#

Add your root key#

Create or update .env.local:

.env.local
Warning
Never commit your root key. Add .env.local to .gitignore.

Create a rate-limited route#

app/api/protected/route.ts

Run your app#

Test it#

First 10 requests return 200. Requests 11+ return 429:

Wait 60 seconds and the limit resets.

What's in the response?#

limiter.limit() returns:

FieldTypeDescription
successbooleantrue if request is allowed, false if rate limited
remainingnumberRequests remaining in current window
resetnumberUnix timestamp (ms) when the window resets
limitnumberThe configured limit

Choosing an identifier#

The identifier determines who gets rate limited. Common choices:

IdentifierUse caseExample
User IDAuthenticated usersreq.auth.userId
API keyPer-key limitsreq.headers.get("x-api-key")
IP addressAnonymous/public endpointsreq.headers.get("x-forwarded-for")
ComboExtra specificity${userId}:${endpoint}

Creating a reusable limiter#

For cleaner code, create a utility:

lib/ratelimit.ts

Then use in routes:

app/api/login/route.ts

Next steps#

Troubleshooting#

Rate limit not working?
  • Check that UNKEY_ROOT_KEY is set in .env.local - Verify your root key has ratelimit.*.limit permission - Make sure you're using the same identifier each request - Restart the dev server after changing .env.local
Getting network errors?
Want different limits per route?

Create multiple Ratelimit instances with different namespaces and limits. Each namespace tracks limits independently.