Rate limiting caps how many requests a single client can make within a period of time. It protects endpoints from abuse: without it, an attacker can try thousands of passwords per minute against a login, hammer an API, or drive up your usage bills. When the limit is exceeded, the server rejects further requests until the window resets.
Where it matters most
Login and password-reset routes are the priority, because unlimited attempts turn a weak password into an easy break-in. It also matters on any expensive or costly operation, such as an endpoint that calls a paid API, where volume alone is the attack.
How it is applied
A limiter tracks requests per client, usually keyed on the real IP or the account, and blocks once a threshold in a time window is passed. It should key on the true socket IP, not a header a client can set, and back sensitive routes with a short window and a low count.
What this means for AI-generated code
AI tools generate a login that authenticates correctly but almost never add rate limiting, because the feature works fine without it. That leaves the door open to automated password guessing, one of the easiest attacks to run at scale.
Common questions
How do I add rate limiting to a Next.js API route?
Use a library like upstash/ratelimit (backed by Redis) or rate-limiter-flexible. Key the limiter on the real IP (from request.headers.get('x-forwarded-for') on Vercel, not req.socket.remoteAddress which is always the edge node IP) and set a window and count appropriate for the endpoint — for login, 5-10 attempts per 15 minutes per IP is a common starting point.
What is the right IP to key rate limiting on?
The real client IP, not the proxy or load balancer IP. On Vercel, use the x-real-ip or x-forwarded-for header (first IP in the list). On Cloudflare, use cf-connecting-ip. Never key on a header the client can set directly, like x-forwarded-for without validation, as attackers can rotate it.
Should rate limiting be on the client side or server side?
Always server side. Client-side limits can be bypassed by sending requests directly to the API endpoint, skipping the UI entirely. Server-side rate limiting enforced on every request, regardless of where the call originates, is the only effective control.