La feature más importante de Next.js 16 no es nueva. Se desplegó en octubre de 2022
En 2022, Next.js invirtió silenciosamente React.
Cada componente que escribes es ahora un Server Component por defecto. La ejecución en cliente es la excepción, no la regla. Y el `fetch` dentro de `useEffect` —el patrón que alimentó los últimos cinco años de apps React— se ha convertido en el mayor motivo de que tu Next.js vaya lento.
Cuando la gente busca "nextjs 16 new features", espera una lista de funciones. Velocidades de build. Turbopack. Pero la historia real no es esa.
*El problema no es que Next.js vaya lento. Es que tu arquitectura decide que vaya lento. *
Desde Next.js 13 (octubre de 2022), el App Router invirtió el modelo mental de React: la ejecución en servidor es el default y optas fuera con `'use client'` en el borde interactivo. La mayoría de los que reportan "migramos y fue más lento" todavía escriben React client-first: fetch en `useEffect`, caching desactivado globalmente, lecturas de cookies que fuerzan toda la ruta a dinámica.
¿Qué trae de verdad Next.js 16? Turbopack como bundler por defecto para dev y production builds. Escrito en Rust. Fue el sustituto de webpack. Y los async request APIs que Next.js 15 (octubre 2024) introdujo —`cookies()`, `headers()`, `params`, `searchParams` ahora se hacen con `await`— rompen middlewares y Server Actions escritos con el patrón antiguo.
Pero nada de eso importa si sigues arquitectando con el manual de 2020.
El problema: estás arquitectando un framework nuevo con hábitos viejos
En el Pages Router (antes de Next.js 13), el render en servidor era una elección explícita. Escribías `getServerSideProps` si querías SSR. El resto era cliente. La lógica de render estaba clara: todo cliente, a menos que digas lo contrario.
El App Router lo invierte por completo: todo servidor, a menos que escribas `'use client'`. Dos mentalidades opuestas que conviven en el mismo ecosistema.
¿Qué pasa cuando un equipo migra sin cambiar la mentalidad? Esto:
❌ `useEffect` que hace fetch de datos tras el primer render (doble render, doble round trip)
❌ Desactivar cache globalmente con `export const dynamic = 'force-dynamic'` porque "los datos cambian a menudo"
❌ Leer `cookies()` en una ruta estática para cambiar un texto de entrada — convirtiendo toda la ruta en dinámica
❌ Componentes que acceden a `window` o `document` sin envoltorio de cliente — error en el server
✅ `fetch` directo en un Server Component `async`
✅ Props serializables hacia abajo, `'use client'` solo en la hoja interactiva
✅ `revalidate` explícito por ruta, no force-dynamic global
✅ Envoltorio cliente mínimo para librerías que tocan APIs del navegador
La migración del Pages Router al App Router no es un rename de carpetas. Es un cambio de arquitectura con costes operativos propios. Un team que migra el código sin migrar el modelo mental no está usando Next.js 16. Está pagando por él.
La evidencia: tres cambios concretos que ya están aquí
1. Turbopack es el bundler por defecto
Next.js 16 hizo de Turbopack el bundler por defecto para development y production builds. Escrito en Rust, reemplaza a webpack como ruta principal. Los cold starts y rebuilds aceleran de forma dramática.
El matiz que la mayoría ignora: algunos plugins y configs de webpack necesitan rework. Si tu proyecto se apoya en loaders webpack personalizados, la checklist de migración de build importa tanto como las features de runtime. No es solo "actualiza y listo".
2. Las Async Request APIs rompen medio ecosistema
Next.js 15 hizo asíncronas las APIs de petición. `cookies()`, `headers()`, `params` y `searchParams` ahora requieren `await`.
```tsx
// ❌ Next.js 14 y anteriores: sincrónico
export default function Page({ params }) {
const id = params.id
return <p>{id}</p>
}
```
```tsx
// ✅ Next.js 15/16: awaited
export default async function Page({ params }) {
const { id } = await params
return <p>{id}</p>
}
```
No es un cambio cosmético. Rompe middlewares, librerías de autenticación y Server Actions que usaban el patrón sincrónico. Es el segundo mayor motivo de "dos semanas perdidas" en equipos que migran.
3. El Server Component como default: fetch sin useEffect
Este es el cambio que más se malinterpreta. En el Pages Router, esto era el patrón estándar:
```tsx
// ❌ El patrón que mató a tu rendimiento
function Dashboard() {
const [data, setData] = useState([])
useEffect(() => {
fetch('/api/data').then(r => r.json()).then(setData)
}, [])
return <ul>{data.map(item => <li key={item.id}>{item.name}</li>)}</ul>
}
```
En el App Router, el reemplazo es directo — sin estado, sin efecto, sin round trip extra:
```tsx
// ✅ Server Component: fetch en el server, sin useEffect
export default async function Dashboard() {
const data = await getData() // llamada directa a la base de datos
return <ul>{data.map(item => <li key={item.id}>{item.name}</li>)}</ul>
}
```
El Server Component se ejecuta en el servidor una vez, pinta HTML y envía props serializables a las hojas interactivas. No hay hidratación de datos. No hay "loading spinner de datos que podría ya tener".
Análisis: por qué "Next.js va lento" es un síntoma, no el diagnóstico
El App Router cachea agresivamente en build time por defecto. Pero una sola lectura de `cookies()` o `headers()` marca toda la ruta como dinámica.
Este es el detalle que te ahorra horas de debugging:
```tsx
// app/blog/[slug]/page.tsx
export const revalidate = 60 // ISR: regenera cada minuto en background
export default async function BlogPost({ params }) {
const { slug } = await params
// Si en cualquier punto de este árbol lees cookies() o headers(),
// esta ruta deja de ser ISR y pasa a ser dinámica al 100%.
// Tu revalidate deja de aplicar. Tu cache muere. Sin error aparente.
const data = await getPost(slug)
return <article>{data.title}</article>
}
```
Añadir middleware de autenticación o leer una cookie mata el ISR y el render estático de todo el segmento de ruta. La mayoría de equipos no lo saben hasta que las métricas de cache caen en picado sin tocar nada.
El que dice "Next.js 16 va lento" casi siempre tiene esto: fetch en `useEffect`, `force-dynamic` global, o una cookie leída en la raíz que dinámiza todo el árbol. No es Next.js. Es tu arquitectura.
Y el trade-off honesto: gran parte del pulido del App Router —tuner de ISR, Edge runtime, optimización de imágenes— está optimizado para la plataforma de Vercel. El self-hosting está soportado, pero algunos ergonomics se degradan. Para un equipo con infraestructura propia, esa es una decisión arquitectónica real, no cheerleading.
El Marco de 5 Rutas para Auditoría del App Router
Un framework que no invento sobre la marcha: el patrón que aplico en cada migración que hago. Cinco pasos, en orden.
Ruta 1: Audita el render por ruta antes de escribir código
Ve ruta por ruta y decide: ¿estática, dinámica o ISR? No defaults dinámico porque tu app vieja usaba `getServerSideProps` en todo. El 80% de las páginas de contenido probablemente son estáticas o ISR.
```tsx
// app/precios/page.tsx — estática en build time
export default async function Pricing() {
const plans = await db.getPlans()
return <PricingCards plans={plans} />
}
// app/blog/[slug]/page.tsx — ISR: regenera cada 60s en background
export const revalidate = 60
```
Ruta 2: Mueve el fetch arriba del árbol
Todo `fetch` a datos que no cambian por usuario debe vivir en un Server Component `async`. Props serializables hacia abajo. `'use client'` solo en la hoja interactiva.
```tsx
// app/cart/page.tsx
export default async function CartPage() {
const items = await getCartItems() // server
return <AddToCartButton items={items} /> // cliente, recibe props
}
// components/AddToCartButton.tsx
'use client'
export default function AddToCartButton({ items }) {
return <button onClick={() => addItem(items)}>Añadir al carrito</button>
}
```
La hoja interactiva sigue corriendo 100% en el cliente. No es una red de round trips por click. El borde es tuyo: elígelo donde haga falta.
Ruta 3: Adopta el streaming deliberadamente
Envuelve llamadas lentas a bases de datos o APIs terceras en `<Suspense>` para que el shell pinte de inmediato y lo lento streamee después.
```tsx
// app/dashboard/page.tsx
import { Suspense } from 'react'
import { AnalyticsChart } from './analytics-chart'
export default function Dashboard() {
return (
<div>
<h1>Panel</h1>
<Suspense fallback={<ChartSkeleton />}>
<AnalyticsChart /> {/ parte lenta: streamea al pintar /}
</Suspense>
</div>
)
}
```
Trata los ficheros `loading.tsx` como el skeleton por defecto. Es gratis y da una experiencia inmediata.
Ruta 4: Conoce los disparadores de cache
Aprende qué APIs (`cookies()`, `headers()`, `searchParams`) te optan automáticamente a render dinámico. Y define `revalidate` de forma explícita por ruta, nunca desactives cache globalmente.
Ruta 5: Migra por etapas desde Pages Router
Convierte de forma incremental usando route groups. Mantén ambos routers funcionando durante la transición. Migra primero las páginas de más tráfico para medir el impacto real antes de tocar el resto.
```tsx
// app/
// (marketing)/
// page.tsx ← App Router: estática, Turbopack, ISR
// about/page.tsx
// pages/
// _app.tsx ← Pages Router: aún operativo
// checkout.tsx ← se migra en la fase 2
```
La fricción número uno que casi nadie te avisa: el ecosistema
Cuando reportan "está roto", casi siempre es esto: librerías terceras que tocan `window`, `document` u otras APIs client-only lanzan error en Server Components.
La solución es un patrón pequeño pero que te ahorra dos semanas:
```tsx
'use client'
import dynamic from 'next/dynamic'
// Appolo ha roto decenas de deploys. Este envoltorio es la solución.
const Chart = dynamic(() => import('./real-chart'), { ssr: false })
export default function ClientOnlyChart({ data }) {
return <Chart data={data} />
}
```
Ese patrón es el mayor punto de fricción práctico al adoptar el App Router. Conócelo antes de encontrarlo en producción.
¿Sigue teniendo sentido quedarse en el Pages Router?
Sí. Es una decisión legítima. Si tu app funciona, tus métricas de Core Web Vitals son buenas y no necesitas streaming ni ISR fino, quedarte es una opción razonable.
Pero entiende lo que estás aceptando: el App Router no es un rename. Es otro framework con costes operativos distintos. Si migras, migra el modelo mental con el código. Si no migras, no migres a medias.
Conclusión: la arquitectura antes que la feature
Las new features de Next.js 16 —Turbopack por defecto, Async Request APIs, Server Components como estándar— no te van a hacer rápido por sí solas. Tu arquitectura decide si Next.js va rápido o va lento.
Cuando en 2024 Vercel presentó el App Router con el binario estático vs dinámico, pocos entendieron la factura. Hoy, con Turbopack acelerando builds y el modelo de Server Components maduro, la decisión es clara: aprende el modelo invertido o paga el impuesto de la lógica old-school en cada deploy.
La feature más rentable de Next.js 16 no está en las release notes. Es entender que desde octubre de 2022, todo componente es un Server Component por defecto. Y tu `useEffect` con fetch dentro ya no es el patrón — es el problema.
Lee el artículo completo en brianmenagomez.com
Más sobre mis servicios en brianmenagomez.com
Herramientas: Conversor IAE CNAE · Gestorias cerca de ti · Calculadora IRPF

