Mejores Prácticas de Patrones de Next.js
Un resumen condensado de las 25 mejores prácticas más importantes extraídas de cada página en esta sección.
- Combina Middleware y Layout Auth: Usa middleware de borde para una comprobación rápida de "¿hay una cookie de sesión?" y realiza la verificación real de JWT/base de datos en un Server Component o layout — el middleware no puede consultar una base de datos, así que omitir el segundo paso deja pasar cookies falsificadas.
- Protege Secretos con server-only: Pon
import "server-only"en la parte superior de cualquier módulo que toqueAUTH_SECRET, URLs de base de datos o claves de firma para que un Client Component que lo importe falle la compilación en lugar de filtrar el valor al paquete del navegador. - Refuerza las Cookies de Sesión: Establece
httpOnly: truepara bloquear el acceso de JS,secure: trueen producción para requerir HTTPS, ysameSite: "lax"para protección básica de CSRF;sameSite: "none"además requieresecure: trueo el navegador descarta la cookie completamente. - Usa NextRequest, No Request: Importa
NextRequest/NextResponsedenext/serverpara obtener.nextUrl,.cookies,.geo, y ayudantes estáticos comoNextResponse.json()sin tener que reconstruirlos sobre laRequestWeb. - Espera Parámetros Dinámicos en Route Handlers: En Next.js 15+ el segundo argumento es
{ params: Promise<{ ... }> }; desestructurar sinawait paramsproduce una Promise y tu búsqueda retorna silenciosamenteundefined. - Envuelve request.json en try/catch: Un cuerpo vacío o malformado hace que
await request.json()lance una excepción, así que envu élvelo y retorna{ error: "Invalid JSON" }con estado 400 — o valida con unsafeParsede Zod para entrada completamente tipada. - Retorna un 204 Simple: Para respuestas sin contenido usa
new NextResponse(null, { status: 204 });NextResponse.json(null, { status: 204 })envía la cadena"null"como cuerpo y viola el contrato 204. - Usa Actualizaciones Atómicas para Contadores: Para créditos y límites de velocidad, usa
updateMany({ where: { credits: { gt: 0 } }, data: { credits: { decrement: 1 } } })o "incrementa primero, luego verifica, reviertete en desbordamiento" para cerrar la ventana TOCTOU entre lectura y escritura. - Nunca Pongas Secretos Detrás de NEXT_PUBLIC_: Cualquier variable con el prefijo
NEXT_PUBLIC_se inserta en el paquete del cliente en tiempo de compilación, así que reserva esto para claves publicables y URLs públicas — las URLs de base de datos, claves API y secretos de firma deben permanecer solo en servidor. - Evita process.env Dinámico en el Cliente: Next.js hace reemplazo de cadena estática, no búsqueda en tiempo de ejecución, así que
process.env[varName]siempre esundefineden código de cliente — solo referencias literales comoprocess.env.NEXT_PUBLIC_APP_URLse insertan. - Valida Env con Zod al Inicio: Analiza
process.enva través de un esquema Zod enlib/env.tspara que variables faltantes o malformadas fallen rápidamente con un mensaje claro antes de la primera solicitud, y obtengas un objetoenvcompletamente tipado de forma gratuita. - error.tsx Debe Ser un Client Component: Los Error Boundaries de React dependen del ciclo de vida de clase, así que cada
error.tsxnecesita"use client"en la parte superior; sin ella la compilación falla y ningún límite se instala para ese segmento. - global-error.tsx Renderiza Su Propio html/body: Cuando el propio layout raíz falla,
global-error.tsxreemplaza el documento completo, así que debe renderizar<html><body>…</body></html>; también solo se activa en producción (dev muestra la superposición de Next.js). - Retorna Uniones Discriminadas de Acciones: Tipifica los resultados de Server Action como
{ success: true; data: T } | { success: false; error: string }para fallos de validación esperados, y reservathrowpara errores inesperados que deben activar elerror.tsxmás cercano. - Llama redirect Fuera de try/catch:
redirect()(ynotFound()) lanzan un error de centinelaNEXT_REDIRECT, así que untry/catchcircundante traga la navegación — coloca la llamada después de toda la lógica recuperable o relanza el centinela. - Usa output: standalone y Copia Activos:
output: "standalone"produce un servidor autónomo minimalista y autónomo, pero.next/staticypublic/no se incluyen — cópialos en el directorio standalone (o frente con un CDN/proxy inverso) o los activos estáticos retornarán 404. - Establece HOSTNAME 0.0.0.0 en Docker: El servidor Next.js se vincula a
127.0.0.1de forma predeterminada, que es inaccesible desde fuera de un contenedor; estableceENV HOSTNAME="0.0.0.0"(yENV PORT=3000) en el Dockerfile para que el mapeo de puertos funcione. - Conoce los Límites de Edge Runtime:
runtime = "edge"se ejecuta en un aislamiento V8 sin las built-ins de Node — sinfs,path,child_processoBuffer, y debes usarglobalThis.crypto; retrocede a"nodejs"siempre que necesites esas APIs. - Establece metadataBase en el Layout Raíz: Todos los URLs relativos en
openGraph,twitteryalternatesse resuelven contrametadataBase; sinmetadataBase: new URL("https://myapp.com")tus imágenes OG y canónicas se envían como rutas relativas rotas. - Usa generateMetadata para Páginas Dinámicas: Para títulos por publicación, descripciones e imágenes OG, exporta
async generateMetadata({ params })(params es una Promise en Next.js 15+) y extiende la antecesor a través del argumentoResolvingMetadataen lugar de duplicar campos. - Usa las Convenciones de sitemap.ts y robots.ts: Exportar una función predeterminada de
app/sitemap.tssirve automáticamente/sitemap.xmlyapp/robots.tssirve automáticamente/robots.txt; divide en múltiples Route Handlers de mapa del sitio una vez que un sitio excede el límite de mapa del sitio de 50,000 URLs. - Excluye Activos del i18n Matcher: El middleware de detección de configuración regional debe omitir
_next,apiy archivos con extensiones (p. ej.,matcher: ["/((?!_next|api|favicon.ico).*)"]) o redirige activos estáticos en rutas con prefijo de configuración regional y rompe la página. - Retorna Cada Configuración Regional de generateStaticParams: Prerenderiza todas las configuraciones regionales en tiempo de compilación devolviendo cada una de
generateStaticParams; las configuraciones regionales faltantes retornan silenciosamente 404 en producción a menos quedynamicParamsesté habilitado. - Simula next/headers y next/cache en Pruebas:
cookies(),headers(),revalidatePathyrevalidateTaglanzan excepción fuera del contexto de solicitud de Next.js, así que córtalos convi.mock("next/headers", …)/vi.mock("next/cache", …)antes de importar el módulo bajo prueba. - Espera Server Components Async en Pruebas: Los Server Components son funciones async que retornan JSX, así que en Vitest haz
const jsx = await PostList(); render(jsx)en lugar derender(<PostList />); también simula convi.mock()antes deimport()dinámico para asegurar que la simulación gane.