Next.js 15 ha sido lanzado con muchas funciones innovadoras incluyendo soporte para React 19 y la version estable de Turbopack. Este articulo explica los principales cambios de Next.js 15 que los desarrolladores deben conocer y los metodos de migracion reales.
Resumen de Nuevas Funciones Principales
| Funcion | Estado | Impacto |
|---|---|---|
| Soporte React 19 | Estable | Alto |
| Turbopack Dev | Estable | Alto |
| Prerenderizado Parcial (PPR) | Experimental | Medio |
| API next/after | Estable | Medio |
| Cambio de comportamiento de cache | Cambio disruptivo | Alto |
| Soporte ESLint 9 | Estable | Bajo |
Soporte React 19
Integracion con React 19 RC
Next.js 15 esta estrechamente integrado con React 19.
# Crear nuevo proyecto
npx create-next-app@latest my-app
# Actualizar proyecto existente
npm install next@latest react@rc react-dom@rc
Mejora de Actions
useActionState y useFormStatus de React 19 ahora son soportados nativamente.
// app/actions.ts
'use server';
export async function submitForm(prevState: any, formData: FormData) {
const email = formData.get('email');
// Validacion
if (!email || typeof email !== 'string') {
return { error: 'Por favor ingrese una direccion de correo valida' };
}
// Procesamiento como guardado en base de datos
await saveToDatabase(email);
return { success: true, message: 'Registro completado' };
}
// app/form.tsx
'use client';
import { useActionState } from 'react';
import { useFormStatus } from 'react-dom';
import { submitForm } from './actions';
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? 'Enviando...' : 'Registrar'}
</button>
);
}
export function NewsletterForm() {
const [state, formAction] = useActionState(submitForm, null);
return (
<form action={formAction}>
<input type="email" name="email" placeholder="Direccion de correo" />
<SubmitButton />
{state?.error && <p className="error">{state.error}</p>}
{state?.success && <p className="success">{state.message}</p>}
</form>
);
}
React Compiler (Experimental)
Con React Compiler, ya no se necesitan useMemo o useCallback manuales.
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
experimental: {
reactCompiler: true,
},
};
export default nextConfig;
# Instalar plugin de Babel
npm install babel-plugin-react-compiler
Turbopack Dev Version Estable
Mejora Dramatica de Rendimiento
Turbopack se ha convertido en version estable para modo desarrollo (next dev).
# Iniciar servidor de desarrollo con Turbopack habilitado
next dev --turbo
Resultados de Benchmark
Next.js 15 + Turbopack vs Webpack:
| Metrica | Webpack | Turbopack |
|---|---|---|
| Inicio de servidor local | 4.2s | 1.1s |
| Primera compilacion | 8.5s | 2.3s |
| Fast Refresh | 320ms | 45ms |
| Actualizacion de ruta | 180ms | 25ms |
*Medido en aplicacion grande (1000+ componentes)
Estado de Soporte
// Estado actual de soporte de Turbopack
const turbopackSupport = {
development: 'stable', // Estable
production: 'coming soon', // Proximamente
features: {
appRouter: 'full',
pagesRouter: 'full',
cssModules: 'full',
tailwindCSS: 'full',
sassScss: 'full',
mdx: 'full',
nextImage: 'full',
nextFont: 'full',
},
};
Prerenderizado Parcial (PPR)
Combinacion Optima de Estatico y Dinamico
PPR es una funcion experimental que combina eficientemente partes estaticas y dinamicas dentro de la misma pagina.
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
experimental: {
ppr: 'incremental', // Habilitar por ruta
},
};
export default nextConfig;
// app/dashboard/page.tsx
import { Suspense } from 'react';
import { StaticHeader } from './static-header';
import { DynamicContent } from './dynamic-content';
// Habilitar PPR
export const experimental_ppr = true;
export default function Dashboard() {
return (
<div>
{/* Prerenderizado estaticamente */}
<StaticHeader />
{/* Streaming dinamico */}
<Suspense fallback={<LoadingSkeleton />}>
<DynamicContent />
</Suspense>
</div>
);
}
Flujo de Operacion de PPR
flowchart TB
subgraph BuildTime["Tiempo de Build"]
StaticShell["Shell Estatico<br/>(Header, Layout, Fallback)<br/>→ Pregenerado como HTML"]
end
subgraph RequestTime["Tiempo de Solicitud"]
Step1["1. Devolver shell estatico inmediatamente (TTFB minimizado)"]
Step2["2. Streaming de contenido dinamico"]
Step3["3. Hidratacion gradual en limites Suspense"]
Step1 --> Step2 --> Step3
end
BuildTime --> RequestTime
API next/after
Ejecucion de Procesamiento Post-Respuesta
next/after es una nueva API que permite ejecutar procesamiento despues de devolver la respuesta al cliente.
// app/api/submit/route.ts
import { after } from 'next/server';
export async function POST(request: Request) {
const data = await request.json();
// Devolver respuesta inmediatamente
const result = await processSubmission(data);
// Procesamiento en segundo plano despues de la respuesta
after(async () => {
await sendEmailNotification(data.email);
await logAnalytics('form_submitted', data);
await updateSearchIndex(result.id);
});
return Response.json({ success: true, id: result.id });
}
// Uso en Server Component
import { after } from 'next/server';
export default async function Page() {
const data = await fetchData();
// Ejecutar despues del renderizado de pagina
after(() => {
logPageView('/dashboard');
});
return <Dashboard data={data} />;
}
Casos de Uso
- Envio de analiticas
- Registro de logs
- Calentamiento de cache
- Envio de notificaciones
- Actualizacion de indices de busqueda
Cambio de Comportamiento de Cache
Cambio de Comportamiento por Defecto (Cambio Disruptivo)
En Next.js 15, el comportamiento por defecto del cache ha cambiado significativamente.
// Next.js 14 y anteriores
fetch('https://api.example.com/data');
// Por defecto: force-cache (con cache)
// Next.js 15
fetch('https://api.example.com/data');
// Por defecto: no-store (sin cache)
Especificacion Explicita de Cache
// Para habilitar cache, especificar explicitamente
fetch('https://api.example.com/data', {
cache: 'force-cache',
});
// O especificar revalidate
fetch('https://api.example.com/data', {
next: { revalidate: 3600 }, // 1 hora
});
Cache de Route Handler
// app/api/data/route.ts
// Next.js 14: GET se cachea por defecto
// Next.js 15: sin cache por defecto
export async function GET() {
const data = await fetchData();
return Response.json(data);
}
// Para hacer estatico
export const dynamic = 'force-static';
// O especificar revalidate
export const revalidate = 3600;
Client Router Cache
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
experimental: {
staleTimes: {
dynamic: 30, // Tiempo de cache para paginas dinamicas (segundos)
static: 180, // Tiempo de cache para paginas estaticas (segundos)
},
},
};
Estabilizacion de Instrumentation API
Bootstrap de Aplicacion
// instrumentation.ts (raiz del proyecto)
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
// Ejecutar solo en runtime Node.js
const { initializeDatabase } = await import('./lib/db');
await initializeDatabase();
const { startMetricsCollection } = await import('./lib/metrics');
startMetricsCollection();
}
if (process.env.NEXT_RUNTIME === 'edge') {
// Inicializacion en runtime Edge
console.log('Runtime Edge inicializado');
}
}
export async function onRequestError(
err: Error,
request: Request,
context: { routerKind: string; routePath: string }
) {
// Seguimiento de errores
await reportError(err, {
url: request.url,
...context,
});
}
Mejoras en Experiencia de Desarrollo
Mejora en Visualizacion de Errores
flowchart TB
subgraph ErrorUI["Mejora de UI de Error en Next.js 15"]
Error["Error: Cannot read properties of undefined"]
subgraph SourceCode["Codigo Fuente"]
Line12["12 │ const user = await getUser(id);"]
Line13["13 │ return user.name; ← Ubicacion del error"]
Line14["14 │ }"]
end
subgraph StackTrace["Stack Trace"]
ST1["app/dashboard/page.tsx:13"]
ST2["..."]
end
Actions["[Ver documentacion] [Reportar Issue]"]
Error --> SourceCode --> StackTrace --> Actions
end
Static Indicator
Puede confirmar visualmente el renderizado estatico/dinamico durante el desarrollo.
// Las paginas estaticas muestran un indicador verde
// Las paginas dinamicas muestran un indicador azul
// en la esquina inferior derecha del navegador
Metodo de Actualizacion
Actualizacion Automatica
# Actualizacion automatica usando codemod
npx @next/codemod@canary upgrade latest
Actualizacion Manual
# Actualizar dependencias
npm install next@latest react@rc react-dom@rc
# Para TypeScript
npm install @types/react@rc @types/react-dom@rc
Principales Tareas de Migracion
// 1. Comportamiento de cache de fetch
// Antes (Next.js 14)
fetch('/api/data'); // Con cache
// Despues (Next.js 15)
fetch('/api/data', { cache: 'force-cache' }); // Especificar explicitamente
// 2. Route Handler
// Antes
export async function GET() { ... } // Cache automatico
// Despues
export const dynamic = 'force-static'; // Hacer estatico explicitamente
export async function GET() { ... }
// 3. Importacion de Server Actions
// Antes
'use server';
// Todo el archivo son Server Actions
// Despues (recomendado)
// Separar en actions.ts e importar
import { submitForm } from './actions';
Nueva Estructura de Proyecto (Recomendada)
my-app/
├── app/
│ ├── (auth)/
│ │ ├── login/
│ │ └── signup/
│ ├── (dashboard)/
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── api/
│ │ └── [...route]/
│ ├── actions/ # Server Actions
│ │ └── form.ts
│ ├── layout.tsx
│ └── page.tsx
├── components/
│ ├── ui/
│ └── features/
├── lib/
│ ├── db.ts
│ └── utils.ts
├── instrumentation.ts # Nuevo
├── next.config.ts # De .mjs a .ts
└── package.json
Consejos de Optimizacion de Rendimiento
1. Aprovechar Turbopack
// package.json
{
"scripts": {
"dev": "next dev --turbo",
"build": "next build",
"start": "next start"
}
}
2. Introduccion Gradual de PPR
// Habilitar secuencialmente desde paginas de alto trafico
export const experimental_ppr = true;
3. Estrategia de Cache Apropiada
// Configuracion de cache segun la naturaleza de los datos
const staticData = await fetch('/api/config', {
cache: 'force-cache',
});
const userData = await fetch('/api/user', {
cache: 'no-store', // Siempre mas reciente
});
const productData = await fetch('/api/products', {
next: { revalidate: 60 }, // Actualizar cada minuto
});
Resumen
Next.js 15 ha logrado una gran evolucion tanto en rendimiento como en experiencia de desarrollo.
Principales Puntos de Actualizacion
- Soporte React 19: Nuevos hooks, mejoras en Server Actions
- Turbopack estable: Velocidad de build drasticamente mejorada en desarrollo
- PPR: Combinacion optima de estatico y dinamico
- Cambio de cache: Comportamiento por defecto mas predecible
Puntos a Tener en Cuenta en la Migracion
- El comportamiento de cache de fetch cambia a no-store por defecto
- El cache de Route Handler tambien cambia de manera similar
- Se recomienda migracion gradual usando codemod
Combinado con React 19, Next.js se ha vuelto aun mas poderoso como framework React full-stack.
Enlaces de Referencia
- Post del Blog de Next.js 15
- Documentacion de Next.js
- Notas de Lanzamiento de React 19
- Guia de Actualizacion