Saltar al contenido

Actualizar a Next.js 16: qué falla a gritos y qué cambia en silencio

La mayoría de los cambios incompatibles de 16 detienen el build, y eso los hace seguros. Para los que hay que planificar son los pocos que cambian el comportamiento sin avisar.

5 min de lectura

Next.js 16 trae una lista larga de cambios incompatibles y la mayoría son del tipo bueno: detienen el build. Lo ejecutas, falla, lo arreglas, sigues.

Los que conviene leer con atención son los pocos que cambian el comportamiento sin que nada falle. Esos llegan a producción.

Esto está escrito desde una base de código con 16.3 - el sitio en el que lo estás leyendo.

La única decisión de arquitectura: middleware pasó a ser proxy

middleware.ts queda obsoleto y se renombra a proxy.ts, y la función exportada middleware pasa a llamarse proxy. El renombrado lo hace el codemod.

Lo que el codemod no puede hacer es la decisión que hay debajo, y es real:

El runtime edge no está soportado en proxy. El runtime de proxy es nodejs y no se puede configurar.

Si tu middleware corría en el edge - y por defecto lo hacía -, renombrar el archivo mueve ese trabajo de cien ubicaciones edge a tu servidor Node. Para un rewrite o una redirección de idioma que se ejecuta en cada petición, eso no es un renombrado: es un cambio de dónde viene la latencia.

El camino documentado si necesitas el runtime edge es seguir usando middleware por ahora. Así que la actualización tiene una bifurcación:

  • Trabajo ligero de enrutado - rewrites, redirecciones, leer una cookie - pásalo a proxy y acepta el runtime Node.
  • Cualquier cosa sensible a la latencia en el edge - quédate en middleware hasta que llegue la guía siguiente, sabiendo que estás sobre una convención obsoleta.

En cualquier caso, este es el momento de comprobar si el matcher estuvo bien alguna vez. El middleware se ejecuta en cada petición, incluidas las que olvidaste, y ahora cada una de ellas es un viaje a tu origen.

Con él se renombran los flags de configuración: skipMiddlewareUrlNormalize ahora es skipProxyUrlNormalize. De eso se encarga el codemod.

Lo que falla a gritos, así que no puedes desplegarlo

Una configuración de webpack con next build. Turbopack ahora es el predeterminado también para next build, no solo para next dev, y un proyecto con configuración propia de webpack falla el build a propósito en lugar de ignorarla en silencio. Tres salidas: compilar con --turbopack e ignorar la configuración, portarla a opciones de Turbopack, o salirte con --webpack. Conviene saberlo: puede que un plugin esté añadiendo una opción de webpack que tú no escribiste, que es la versión confusa de este error.

Rutas paralelas sin default.js. Cada slot exige ahora un default.js explícito y el build falla sin él. Un archivo que llame a notFound() o devuelva null restaura el comportamiento anterior.

Node 18. El mínimo es ahora Node 20.9 y TypeScript 5.1. Los navegadores objetivo pasan a Chrome, Edge y Firefox 111+ y Safari 16.4+.

next lint, AMP y la configuración de runtime. Todo eliminado. serverRuntimeConfig y publicRuntimeConfig ya no existen: usa variables de entorno. next/legacy/image queda obsoleto, y también images.domains, al que sustituyó remotePatterns.

Lo que cambia en silencio, que es lo que hay que planificar

El caché de imágenes pasó de 60 segundos a 4 horas. images.minimumCacheTTL vale ahora 14400. Nada da error. Si dependías del valor anterior para refrescar imágenes que cambian durante el día, ya no lo hacen, y el síntoma es una imagen obsoleta que nadie consigue reproducir porque su caché de navegador no coincide con la del optimizador. Vuelve a fijarlo explícitamente si lo necesitas:

// next.config.ts
images: { minimumCacheTTL: 60 },

next build ya no ejecuta lint. Si tu CI contaba con el build para detectar errores de lint, ha dejado de hacerlo en silencio. Además @next/eslint-plugin-next usa ahora flat config por defecto. Ejecuta ESLint o Biome como paso propio, y comprueba que ese paso existe antes de dar por hecho que está en verde.

Los valores por defecto del srcset de imágenes se movieron. Se quitó el 16 del array imageSizes por defecto y cambió el valor de qualities. Ninguno da error; ambos cambian lo que se genera y, por tanto, lo que se cachea y se sirve.

Las imágenes locales con query string ahora necesitan configuración. /photo?v=1 requiere una entrada en images.localPatterns con un search que coincida. Este sí da error, pero solo en las rutas que usan el patrón, que puede que no sean las de tu prueba de humo.

El orden que funciona

  1. Lee la guía antes del codemod. Está en node_modules/next/dist/docs/ desde 16.2, emparejada con la versión que realmente instalaste en lugar de con lo que recuerda internet.
  2. Ejecuta el codemod de actualización y después, por separado, el de las Request APIs asíncronas si todavía tienes params, searchParams, cookies(), headers() o draftMode() síncronos del periodo de compatibilidad de la 15. El codemod de actualización no ejecuta todas las migraciones.
  3. Decide la cuestión de proxy deliberadamente, porque nada te la va a preguntar.
  4. Compara la salida del build con la anterior. Qué rutas son y cuáles ƒ no debería haber cambiado, y si ha cambiado, conviene entenderlo antes de desplegar.
  5. Revisa la lista silenciosa de arriba contra tu propia configuración.

Si vas varias versiones por detrás

El salto de 15 a 16 es manejable. Llegar desde la 13 o la 14 con un Pages Router todavía en el árbol es otro proyecto, y el error es tratarlo como una sola actualización. Migrar sin congelar funcionalidades describe el orden que mantiene la aplicación desplegable mientras ocurre, y migración y rescate es ese trabajo hecho por nosotros.

Volver a todos los artículos