Rate Limiting
Tiered API rate limiting with Upstash Redis. Gracefully degrades to allow-all in development.
Protect API routes from abuse with 3 pre-configured tiers powered by Upstash Redis's sliding window algorithm. Setup takes ~5 minutes.
What's Included
| File | Purpose |
|---|---|
lib/features/rate-limit.ts | rateLimit(req, tier) — returns { success, limit, remaining, reset } |
Tiers
| Tier | Requests | Window | Use Case |
|---|---|---|---|
strict | 10 | 1 minute | Auth endpoints (login, signup, password reset) |
standard | 30 | 1 minute | General CRUD API routes |
lenient | 60 | 1 minute | Read-heavy endpoints (search, listings) |
When UPSTASH_REDIS_REST_URL is not set, the limiter logs a warning and allows all requests through — safe for local development.
Setup
1
Install dependencies
pnpm add @upstash/ratelimit @upstash/redis2
Add environment variables
UPSTASH_REDIS_REST_URL="https://your-region.upstash.io"
UPSTASH_REDIS_REST_TOKEN="your-token"Create a Redis database at upstash.com (free tier: 10,000 req/day). Copy the REST URL and token from the database console.
3
Add to API routes
import { rateLimit } from "@/lib/features/rate-limit"
export async function POST(req: Request) {
const rl = await rateLimit(req, "standard")
if (!rl.success) {
return Response.json(
{ success: false, error: "Too many requests. Please try again later." },
{
status: 429,
headers: {
"X-RateLimit-Limit": String(rl.limit),
"X-RateLimit-Remaining": String(rl.remaining),
"X-RateLimit-Reset": String(rl.reset),
},
}
)
}
// ... your route logic
}Environment Variables
| Variable | Required | Description |
|---|---|---|
UPSTASH_REDIS_REST_URL | No* | Upstash Redis REST URL |
UPSTASH_REDIS_REST_TOKEN | No* | Upstash Redis REST token |
*Not required for development. Rate limiting is bypassed when not set (with a console warning).
Return Value
{
success: boolean // true = request allowed
limit: number // max requests in the window
remaining: number // requests remaining in current window
reset: number // Unix timestamp when the window resets
}Verification
- Add rate limiting to any API route
- Hit it rapidly in a loop (e.g.,
for i in {1..15}; do curl localhost:3000/api/route; done) - After exceeding the tier limit, you should receive
429withX-RateLimit-*headers - Wait for the window to reset — requests allowed again
- Remove env vars locally — confirm requests pass through with a console warning