Nuevas Funciones de Next.js 15 - Soporte para React 19 y Estabilizacion de Turbopack

2025.12.02

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

FuncionEstadoImpacto
Soporte React 19EstableAlto
Turbopack DevEstableAlto
Prerenderizado Parcial (PPR)ExperimentalMedio
API next/afterEstableMedio
Cambio de comportamiento de cacheCambio disruptivoAlto
Soporte ESLint 9EstableBajo

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:

MetricaWebpackTurbopack
Inicio de servidor local4.2s1.1s
Primera compilacion8.5s2.3s
Fast Refresh320ms45ms
Actualizacion de ruta180ms25ms

*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

  1. Soporte React 19: Nuevos hooks, mejoras en Server Actions
  2. Turbopack estable: Velocidad de build drasticamente mejorada en desarrollo
  3. PPR: Combinacion optima de estatico y dinamico
  4. 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

← Volver a la lista