Rate Limiting en Next.js: Protege tus APIs
Implementa rate limiting en tus API routes de Next.js. Limita requests por IP, protege endpoints sensibles y evita abuso con patrones simples.
Rate Limiting en Next.js: Protege tus APIs
Rate limiting es la primera linea de defensa de tus API routes. Sin el, cualquiera puede hacer miles de requests por segundo a tu endpoint de login, agotar tu cuota de base de datos, o disparar tu factura de Vercel. Es trivial de implementar y critico para produccion.
Si tu app tiene endpoints publicos (login, registro, contacto, webhooks), necesitas rate limiting. Punto.
Rate limiter simple (en memoria)
Para proyectos chicos o entornos de una sola instancia, un Map en memoria es suficiente:
// lib/rate-limit.ts
const requests = new Map<string, { count: number; resetTime: number }>();
export function rateLimit(
ip: string,
limit: number = 10,
windowMs: number = 60_000
): { allowed: boolean; remaining: number } {
const now = Date.now();
const record = requests.get(ip);
// Primera request o ventana expirada
if (!record || now > record.resetTime) {
requests.set(ip, { count: 1, resetTime: now + windowMs });
return { allowed: true, remaining: limit - 1 };
}
// Dentro de la ventana
if (record.count < limit) {
record.count++;
return { allowed: true, remaining: limit - record.count };
}
// Limite alcanzado
return { allowed: false, remaining: 0 };
}Usarlo en una API route
// app/api/contacto/route.ts
import { NextResponse } from "next/server";
import { rateLimit } from "@/lib/rate-limit";
export async function POST(request: Request) {
const ip = request.headers.get("x-forwarded-for") ?? "unknown";
const { allowed, remaining } = rateLimit(ip, 5, 60_000); // 5 por minuto
if (!allowed) {
return NextResponse.json(
{ error: "Demasiadas solicitudes. Intenta en un minuto." },
{
status: 429,
headers: { "Retry-After": "60" },
}
);
}
// Procesar la request normalmente
const body = await request.json();
// ... tu logica aqui
return NextResponse.json(
{ ok: true },
{ headers: { "X-RateLimit-Remaining": String(remaining) } }
);
}Rate limiting con Upstash (serverless)
En serverless (Vercel, Cloudflare), cada invocacion puede correr en una instancia diferente. Un Map en memoria no sirve porque cada instancia tiene su propio Map. Necesitas un store compartido.
Upstash tiene Redis serverless con un plan gratuito de 10K requests/dia:
npm install @upstash/ratelimit @upstash/redis// lib/rate-limit.ts
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
export const rateLimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, "60 s"), // 10 requests por minuto
analytics: true,
});// app/api/login/route.ts
import { NextResponse } from "next/server";
import { rateLimit } from "@/lib/rate-limit";
export async function POST(request: Request) {
const ip = request.headers.get("x-forwarded-for") ?? "unknown";
const { success, remaining } = await rateLimit.limit(ip);
if (!success) {
return NextResponse.json(
{ error: "Demasiados intentos" },
{ status: 429, headers: { "Retry-After": "60" } }
);
}
// ... tu logica de login
}Dos lineas de config, una linea para verificar. Upstash se encarga del almacenamiento distribuido.
Rate limiting en middleware (global)
Si quieres proteger TODAS tus API routes:
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
const requests = new Map<string, { count: number; resetTime: number }>();
export function middleware(request: NextRequest) {
// Solo aplicar a API routes
if (!request.nextUrl.pathname.startsWith("/api")) {
return NextResponse.next();
}
const ip = request.headers.get("x-forwarded-for") ?? "unknown";
const now = Date.now();
const record = requests.get(ip);
if (!record || now > record.resetTime) {
requests.set(ip, { count: 1, resetTime: now + 60_000 });
return NextResponse.next();
}
if (record.count >= 30) { // 30 requests por minuto global
return NextResponse.json(
{ error: "Rate limit exceeded" },
{ status: 429 }
);
}
record.count++;
return NextResponse.next();
}Limites recomendados
| Endpoint | Limite | Razon |
|---|---|---|
| Login | 5/min por IP | Prevenir brute force |
| Registro | 3/min por IP | Prevenir spam de cuentas |
| Contacto | 2/min por IP | Prevenir spam |
| API general | 30/min por IP | Uso normal |
| Webhooks | 100/min por IP | Los servicios envian rafagas |
Siguiente paso
Rate limiting es una capa de seguridad. Para proteccion mas completa, revisa la guia de seguridad en aplicaciones Next.js y la guia de headers de seguridad para CSP, HSTS y demas.
Preguntas frecuentes
Que es rate limiting?
Es una tecnica que limita cuantas requests puede hacer un usuario o IP en un periodo de tiempo. Si alguien hace 100 requests por segundo a tu API, el rate limiter bloquea las requests que excedan el limite y responde con un 429 Too Many Requests.
Necesito rate limiting si uso Vercel?
Si. Vercel tiene protecciones basicas contra DDoS, pero no limita el uso de tus API routes. Un bot puede hacer miles de requests a tu endpoint de login, y tu pagas por cada invocacion de serverless function.
Donde guardo el contador de requests?
Para una sola instancia, un Map en memoria funciona. Para multiples instancias o serverless, necesitas un store externo como Redis (Upstash tiene un plan gratuito) o una base de datos.
Que codigo HTTP devuelvo cuando limito?
429 Too Many Requests. Incluye un header Retry-After con los segundos que el cliente debe esperar antes de reintentar.
Articulos relacionados
Headers de Seguridad: Que Son y Como Configurarlos en tu Aplicacion Web
Guia practica sobre headers de seguridad HTTP. CSP, HSTS, X-Frame-Options, Referrer-Policy y como implementarlos en NextJS con next.config.ts y middleware.
Seguridad en Aplicaciones NextJS: Guia Completa para Desarrolladores
Guia practica de seguridad en NextJS. XSS, CSRF, SQL Injection, autenticacion, middleware, rate limiting, CSP headers y checklist de seguridad antes de deploy.