Memorizar una lista de códigos de estado es fácil; elegir el correcto es lo difícil. La diferencia entre "no pude encontrar este registro" y "no tienes permiso para ver este registro" en una API, que un POST se convierta en GET durante una redirección, que Google elimine una dirección de su índice por una página de error: todo se reduce a elegir el número de tres cifras adecuado.
Este artículo tiene dos partes: primero, una lista completa (úsala como referencia) y después los códigos que más se eligen mal en la práctica y cómo aparecen en Next.js.
Cinco clases
| Clase | Significado | En breve |
|---|---|---|
| 1xx | Informativa | Solicitud recibida, el procesamiento continúa |
| 2xx | Éxito | Solicitud procesada correctamente |
| 3xx | Redirección | Se necesita una acción adicional para completarla |
| 4xx | Error del cliente | El error está en el lado del cliente |
| 5xx | Error del servidor | El error está en el lado del servidor |
La distinción parece simple, pero hay casos límite: el cliente envió una solicitud válida, el servidor funciona correctamente, pero una regla de negocio lo prohíbe. ¿Es 4xx o 5xx? (Respuesta: 4xx. Detalles más abajo.)
1xx — Informativos
| Código | Nombre | Significado |
|---|---|---|
| 100 | Continue | El cliente puede seguir enviando el cuerpo de la solicitud |
| 101 | Switching Protocols | El servidor cambia al protocolo indicado en la cabecera Upgrade (handshake de WebSocket) |
| 102 | Processing | Solicitud recibida, aún sin resultado (WebDAV) |
| 103 | Early Hints | Pista de precarga de recursos mediante la cabecera Link antes de que la respuesta final esté lista |
En la práctica, 103 Early Hints es el único 1xx moderno que realmente resulta útil: mientras el servidor prepara la respuesta principal, puede decirle al navegador "empieza a descargar este CSS y esta fuente por adelantado".
2xx — Éxito
| Código | Nombre | Significado |
|---|---|---|
| 200 | OK | La solicitud tuvo éxito; el significado varía según el método HTTP |
| 201 | Created | Se creó un nuevo recurso (normalmente POST/PUT) |
| 202 | Accepted | Recibida pero aún no procesada, para trabajos asíncronos |
| 203 | Non-Authoritative Information | Los metadatos no provienen del servidor de origen (poco común; prefiere 200) |
| 204 | No Content | Éxito, sin cuerpo; las cabeceras pueden ser relevantes |
| 205 | Reset Content | El cliente debe restablecer la vista del documento |
| 206 | Partial Content | Respuesta parcial a una solicitud Range (streaming de vídeo, reanudar descargas) |
| 207 | Multi-Status | Estado independiente para varios recursos (WebDAV) |
| 208 | Already Reported | Evita volver a enumerar los miembros (WebDAV) |
| 226 | IM Used | Respuesta devuelta mediante codificación delta |
Consejo: Usa 201 y 204
La mayoría de las APIs devuelven 200 para todo. Pero cuando un endpoint de creación devuelve 201 Created + una cabecera Location, y uno de eliminación devuelve 204 No Content, el cliente sabe de inmediato qué ocurrió sin tener que interpretar un cuerpo.
3xx — Redirección
| Código | Nombre | ¿Conserva el método? | ¿Permanente? |
|---|---|---|---|
| 300 | Multiple Choices | — | — |
| 301 | Moved Permanently | No (los navegadores cambian POST a GET) | Permanente |
| 302 | Found | No (POST → GET) | Temporal |
| 303 | See Other | No: siempre cambia a GET | Temporal |
| 304 | Not Modified | — (respuesta en cache) | — |
| 305 | Use Proxy | ⚠️ Obsoleto | — |
| 306 | (sin uso) | ⚠️ Reservado | — |
| 307 | Temporary Redirect | Sí | Temporal |
| 308 | Permanent Redirect | Sí | Permanente |
Toda esta tabla se resume en una sola distinción: ¿se conserva el método HTTP después de redirigir?
- 301 / 302 son códigos heredados. Los navegadores convierten las solicitudes POST en GET con ellos; aunque la especificación no lo dijera estrictamente, es el estándar de facto.
- 307 / 308 se introdujeron para aclarar esta ambigüedad: el método que se usó se mantiene sin cambios. Si rediriges un POST, se envía como POST.
- 303 hace justo lo contrario a propósito: fuerza el método a GET sin importar lo que llegó.
Explicación: ¿Para qué sirve 303?
Cuando un usuario envía un formulario, quieres redirigirlo a una página de resultado. Si usas 307, llegará a la página de resultado también con una solicitud POST; si recarga la página, el navegador pregunta "¿quieres reenviar el formulario?" y podrías acabar con registros duplicados. 303 evita esta trampa forzando la solicitud a GET. Este patrón se llama POST/Redirect/GET y es crítico en flujos como los callbacks de pago.
Advertencia: Impacto en SEO
Usa 301/308 para movimientos permanentes; los motores de búsqueda eliminarán la URL antigua de su índice y transferirán la autoridad de los enlaces a la nueva. Si usas 302/307, la URL antigua sigue indexada. Equivocarte en esta elección durante las migraciones de un sitio es una de las causas más comunes de pérdida de tráfico.
4xx — Error del cliente
| Código | Nombre | Significado |
|---|---|---|
| 400 | Bad Request | La solicitud está mal formada: sintaxis no válida, el cuerpo no se puede interpretar |
| 401 | Unauthorized | En realidad significa "no autenticado": se requiere iniciar sesión |
| 402 | Payment Required | Se requiere pago; sin uso estándar |
| 403 | Forbidden | El servidor sabe quién eres, pero no tienes permiso |
| 404 | Not Found | El recurso no existe, o quieres ocultar su existencia |
| 405 | Method Not Allowed | El método se reconoce pero no está soportado en este recurso |
| 406 | Not Acceptable | La negociación de contenido no produjo ningún formato aceptable |
| 407 | Proxy Authentication Required | Como 401, pero para un servidor proxy |
| 408 | Request Timeout | Conexión inactiva cerrada por el servidor |
| 409 | Conflict | La solicitud entra en conflicto con el estado actual del recurso |
| 410 | Gone | Eliminado de forma permanente, la dirección ya no existe |
| 411 | Length Required | Se requiere la cabecera Content-Length |
| 412 | Precondition Failed | Falló la precondición de una solicitud condicional |
| 413 | Content Too Large | El cuerpo de la solicitud supera los límites del servidor |
| 414 | URI Too Long | La URL de destino es demasiado larga |
| 415 | Unsupported Media Type | El formato del payload de la solicitud no está soportado |
| 416 | Range Not Satisfiable | No se puede cumplir el rango solicitado |
| 417 | Expectation Failed | No se pudo cumplir la expectativa de la cabecera Expect |
| 418 | I'm a teapot | Código de broma (RFC 2324): las teteras no pueden preparar café |
| 421 | Misdirected Request | Solicitud enviada al servidor equivocado |
| 422 | Unprocessable Content | La sintaxis es correcta, pero el contenido semántico no es válido |
| 423 | Locked | El recurso está bloqueado (WebDAV) |
| 424 | Failed Dependency | Falló una solicitud anterior (WebDAV) |
| 425 | Too Early | Se niega a procesar una solicitud que podría ser reproducida (early data de TLS 1.3) |
| 426 | Upgrade Required | El cliente debe actualizar el protocolo |
| 428 | Precondition Required | Se requiere una solicitud condicional; evita el problema de la "actualización perdida" |
| 429 | Too Many Requests | Se superó el límite de solicitudes (rate limit) |
| 431 | Request Header Fields Too Large | Las cabeceras son demasiado grandes |
| 451 | Unavailable For Legal Reasons | Acceso bloqueado por motivos legales |
¿401 o 403?
La pareja que más se confunde. Sus nombres inducen a error, porque 401 en realidad significa "no autenticado":
- 401 — No sé quién eres. Inicia sesión. (Sin sesión o con un token no válido.)
- 403 — Sé quién eres, pero no puedes acceder a este recurso. (Un usuario con el rol
userintentando entrar a/admin.)
Consejo: Una tercera opción: 404
A veces incluso 403 revela demasiado. Decir "este recurso existe, pero no puedes verlo" filtra información. Devolver 404 para ocultar por completo la existencia de un recurso, como hace GitHub con los repositorios privados, es un enfoque legítimo.
¿400 o 422?
- 400 — No pude interpretar la solicitud. JSON corrupto, falta un campo obligatorio, tipo de dato incorrecto.
- 422 — La interpreté y el formato es válido, pero el significado no lo es. "La fecha de fin no puede ser anterior a la de inicio", "este correo ya está registrado".
En otras palabras: un error de sintaxis es 400, una violación de una regla de negocio es 422. En la práctica, muchas APIs devuelven 400 para ambos, lo cual está bien; pero si los separas, las aplicaciones cliente pueden distinguir "corrige el formulario" de "corrige el formato de la solicitud" sin código adicional.
409 y 410
- 409 Conflict — La solicitud entra en conflicto con el estado actual del recurso. Un conflicto de versiones por edición concurrente, o intentar crear un recurso con un slug que ya existe.
- 410 Gone — El recurso existió, se eliminó de forma permanente y no volverá. La diferencia con
404es la certeza: los motores de búsqueda desindexan un410mucho más rápido. Si no estás seguro, quédate con404.
429 y Retry-After
Si implementas rate limiting, devolver solo 429 es la mitad del trabajo. Envía también una cabecera Retry-After, para que el cliente sepa cuánto esperar en lugar de reintentar a ciegas.
Ejemplo: Rate limiting en un Route Handler de Next.js
export async function POST(req: Request) {
const allowed = await rateLimit(req);
if (!allowed) {
return new Response(
JSON.stringify({ error: "Çok fazla istek gönderdiniz." }),
{
status: 429,
headers: {
"Content-Type": "application/json",
"Retry-After": "60", // seconds
},
}
);
}
// ...
}451
Se usa cuando el contenido se bloquea por motivos legales. Debe su nombre a la novela Fahrenheit 451 de Ray Bradbury, la temperatura a la que arde el papel.
5xx — Error del servidor
| Código | Nombre | Significado |
|---|---|---|
| 500 | Internal Server Error | Error genérico; el servidor encontró una condición inesperada |
| 501 | Not Implemented | El servidor no soporta el método de la solicitud |
| 502 | Bad Gateway | El proxy recibió una respuesta no válida del servidor upstream |
| 503 | Service Unavailable | El servidor no puede atender la solicitud temporalmente (mantenimiento, sobrecarga) |
| 504 | Gateway Timeout | El servidor upstream no respondió a tiempo |
| 505 | HTTP Version Not Supported | Versión de HTTP no soportada |
| 506 | Variant Also Negotiates | Error de configuración del servidor (negociación circular) |
| 507 | Insufficient Storage | Espacio de almacenamiento agotado (WebDAV) |
| 508 | Loop Detected | Se detectó un bucle infinito (WebDAV) |
| 510 | Not Extended | La extensión HTTP requerida no está soportada |
| 511 | Network Authentication Required | El cliente debe autenticarse para obtener acceso a la red (portal wifi) |
502, 503, 504: ¿qué fallo es cada uno?
Estos tres son la forma más rápida de diagnosticar problemas de despliegue en el servidor:
- 502 Bad Gateway — Nginx está activo, pero la app que hay detrás se ha caído o no responde en ese puerto. Revisa los logs de tu app.
- 503 Service Unavailable — El servidor está activo, pero se niega a atender tráfico ahora mismo: modo mantenimiento, sobrecarga del sistema, ninguna instancia disponible en el pool. Debe enviarse con
Retry-Aftery no debe cachearse. - 504 Gateway Timeout — La app upstream existe pero es demasiado lenta; el proxy dejó de esperar. Busca consultas lentas o llamadas lentas a APIs externas.
Precaución: No devuelvas 200 en modo mantenimiento
Servir una página de "Estamos en mantenimiento" con estado 200 engaña a los motores de búsqueda para que piensen que esa página es tu contenido real. Las páginas de mantenimiento deben devolver 503: los motores de búsqueda no penalizarán tu posicionamiento por interrupciones breves.
Códigos de estado en Next.js
El framework elige algunos códigos de estado por ti, y saber cuáles elige por debajo ayuda.
Importante: Funciones de redirección
redirect()→ 307 (temporal, conserva el método)permanentRedirect()→ 308 (permanente, conserva el método)redirect()dentro del envío de un formulario con Server Action → 303 (para que el navegador continúe con GET; si JS está activo, la navegación del lado del cliente lo gestiona de todos modos)NextResponse.redirect()→ por defecto 307
Next.js elige 307/308 en lugar de 302/301 por el problema de conservación del método mencionado antes: un navegador que recibe 302 convierte POST en GET, de modo que un POST a /users se convierte en un GET a /people.
Si vas a hacer un cambio de dirección permanente, usa permanentRedirect() en lugar de redirect(), o define permanent: true dentro de la configuración redirects() de tu next.config.ts. De lo contrario, los motores de búsqueda no desindexarán la dirección antigua.
Llamar a notFound() devuelve 404 y renderiza tu archivo not-found.tsx.
Ejemplo: Códigos de estado correctos en un Route Handler
import { NextResponse } from "next/server";
export async function POST(req: Request) {
const body = await req.json().catch(() => null);
if (!body) {
return NextResponse.json({ error: "Geçersiz JSON" }, { status: 400 });
}
const parsed = schema.safeParse(body);
if (!parsed.success) {
// Valid format, invalid meaning
return NextResponse.json(
{ error: "Doğrulama hatası", issues: parsed.error.issues },
{ status: 422 }
);
}
const session = await auth();
if (!session) {
return NextResponse.json({ error: "Giriş gerekli" }, { status: 401 });
}
if (session.user.role !== "admin") {
return NextResponse.json({ error: "Yetkiniz yok" }, { status: 403 });
}
const created = await db.post.create({ data: parsed.data });
return NextResponse.json(created, {
status: 201,
headers: { Location: `/api/posts/${created.id}` },
});
}Guía rápida de decisión
Resumen: ¿Qué código debo devolver?
- Registro creado → 201 +
Location - Eliminado, nada que devolver → 204
- URL cambiada de forma permanente → 308 (
301también es aceptable para SEO) - Redirigir a la página de resultado tras enviar un formulario → 303
- No autenticado → 401
- Autenticado pero sin autorización → 403
- Hay que ocultar la existencia del registro → 404
- JSON corrupto → 400
- JSON válido, violación de una regla de negocio → 422
- Conflicto de edición concurrente → 409
- Límite de solicitudes superado → 429 +
Retry-After - En mantenimiento → 503 +
Retry-After - Error inesperado → 500 (escribe el motivo real en los logs, no al usuario)
Una última nota: nunca expongas stack traces a los usuarios en las respuestas de error. Los códigos de estado le dicen al cliente qué acción tomar; los detalles granulares pertenecen a los logs del servidor.
Nota: Fuentes
La lista de códigos de estado se basa en la referencia de códigos de estado de respuesta HTTP de MDN, y los comportamientos de Next.js siguen la documentación de redirect.
Hoja de ruta y herramienta interactivas
Desarrollador Frontend Junior 2026
Lo que realmente necesitas saber para conseguir un trabajo de frontend junior en 2026 y lo que puede esperar, a partir de ofertas reales.
¿SQL o NoSQL?
Responde seis preguntas y te diré qué tipo de base de datos encaja con tu proyecto, y por qué.