Los errores que se repiten.
Next.js es poderoso pero tiene una curva de aprendizaje real, especialmente con el App Router. Los mismos errores aparecen una y otra vez en proyectos de developers que vienen de Create React App o de versiones anteriores de Next.js. Esta guía cubre los más frecuentes con la solución directa para cada uno.
Hydration errors.
El hydration error aparece cuando el HTML renderizado en el servidor no coincide con lo que React intenta renderizar en el cliente. El mensaje típico: "Hydration failed because the initial UI does not match what was rendered on the server". Las causas más comunes: usar new Date() sin formateo consistente (el servidor puede estar en otra zona horaria), acceder a window o localStorage directamente en un componente server, o renderizar contenido basado en Math.random().
La solución depende del caso: para fechas, usá una librería que formatee de forma consistente o asegurate de usar UTC. Para código que solo debe correr en el cliente, usá useEffect con useState para renderizar después del montaje. Para casos donde la diferencia es intencional e inofensiva (como timestamps en comentarios), suppressHydrationWarning={true} en el elemento específico.
'use client' mal usado.
El error más conceptual: marcar componentes como 'use client' innecesariamente. En App Router, los componentes son Server Components por defecto, lo que significa que se renderizan en el servidor y envían HTML puro al cliente. Solo necesitás 'use client' cuando usás hooks de React (useState, useEffect, useRef), event handlers, o APIs del browser (localStorage, window).
Marcar 'use client' innecesariamente no rompe nada, pero aumenta el JavaScript que se envía al cliente y elimina los beneficios de rendimiento de los Server Components. La estrategia correcta: empezá con Server Components y solo convertí a Client Component cuando sea necesario. Mové el estado hacia las hojas del árbol de componentes, no hacia la raíz.
Fetch y caché.
Next.js extiende el fetch nativo con caché automático. Por defecto en Next.js 14+, el fetch en Server Components usa cache: 'force-cache' (siempre cachea). Si necesitás datos frescos, usás { cache: 'no-store' } o { next: { revalidate: 60 } } para ISR. El error común: asumir que el fetch en producción se comporta como en desarrollo. En dev, el caché está deshabilitado. En producción, el caché puede servirte datos viejos si no configuraste correctamente la revalidación.
Imágenes sin optimizar.
Usar <img> HTML directo en lugar del componente <Image> de Next.js es el error que más impacta en performance. El componente Image de Next.js optimiza automáticamente: convierte a WebP/AVIF, genera versiones para diferentes tamaños de pantalla, implementa lazy loading por defecto, y evita layout shift reservando el espacio. Para imágenes de fuentes externas, hay que agregar el dominio en nextConfig.images.remotePatterns.
Routing y params.
En el App Router de Next.js 14+, los params de rutas dinámicas son Promises: const { slug } = await params, no const { slug } = params. Este cambio en Next.js 15 rompió muchos proyectos al actualizar. También es común olvidar que generateStaticParams es necesario para que las rutas dinámicas se pre-generen en el build. Sin él, las páginas son server-rendered on demand, lo que puede causar tiempos de carga más lentos en cold start.
El patrón común.
La mayoría de estos errores comparten un origen: asumir que Next.js App Router se comporta como una SPA de React. No es así. Es un framework full-stack donde el servidor y el cliente tienen roles distintos, el caché es intencional y configurable, y los componentes tienen propiedades diferentes según dónde se renderizan. Entender ese modelo mental es la clave para dejar de pelear contra el framework.