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#
- Unkey account (free)
- Root key with
ratelimit.*.limitpermission - Node.js 18+
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:
| Field | Type | Description |
|---|---|---|
success | boolean | true if request is allowed, false if rate limited |
remaining | number | Requests remaining in current window |
reset | number | Unix timestamp (ms) when the window resets |
limit | number | The configured limit |
Choosing an identifier#
The identifier determines who gets rate limited. Common choices:
| Identifier | Use case | Example |
|---|---|---|
| User ID | Authenticated users | req.auth.userId |
| API key | Per-key limits | req.headers.get("x-api-key") |
| IP address | Anonymous/public endpoints | req.headers.get("x-forwarded-for") |
| Combo | Extra 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_KEYis set in.env.local- Verify your root key hasratelimit.*.limitpermission - Make sure you're using the same identifier each request - Restart the dev server after changing.env.local
Getting network errors?
- Unkey's SDK retries failed requests automatically - If errors persist, check status.unkey.com - Check status.unkey.com if issues persist
Want different limits per route?
Create multiple Ratelimit instances with different namespaces and limits.
Each namespace tracks limits independently.