Novas Funcionalidades do Next.js 15 - Suporte ao React 19 e Estabilização do Turbopack

2025.12.02

O Next.js 15 foi lançado, adicionando muitas funcionalidades inovadoras, como suporte ao React 19 e a versão estável do Turbopack. Este artigo explica as principais mudanças do Next.js 15 que os desenvolvedores devem conhecer e como realizar a migração.

Resumo das Principais Novas Funcionalidades

FuncionalidadeStatusImpacto
Suporte ao React 19EstávelAlto
Turbopack DevEstávelAlto
Pré-renderização Parcial (PPR)ExperimentalMédio
API next/afterEstávelMédio
Mudanças no comportamento do cacheMudança quebradaAlto
Suporte ao ESLint 9EstávelBaixo

Suporte ao React 19

Integração com o React 19 RC

O Next.js 15 está integrado de forma estreita com o React 19.

# Criar novo projeto
npx create-next-app@latest my-app

# Upgrade de projeto existente
npm install next@latest react@rc react-dom@rc

Melhorias nas Actions

O useActionState e useFormStatus do React 19 agora são suportados nativamente.

// app/actions.ts
'use server';

export async function submitForm(prevState: any, formData: FormData) {
  const email = formData.get('email');

  // Validação
  if (!email || typeof email !== 'string') {
    return { error: 'Por favor, insira um endereço de e-mail válido' };
  }

  // Processamento como salvar no banco de dados
  await saveToDatabase(email);

  return { success: true, message: 'Registro concluído' };
}
// 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="Endereço de e-mail" />
      <SubmitButton />
      {state?.error && <p className="error">{state.error}</p>}
      {state?.success && <p className="success">{state.message}</p>}
    </form>
  );
}

React Compiler (Experimental)

O React Compiler elimina a necessidade de useMemo e useCallback manuais.

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  experimental: {
    reactCompiler: true,
  },
};

export default nextConfig;
# Instalar plugin Babel
npm install babel-plugin-react-compiler

Turbopack Dev Estável

Melhoria Dramática de Desempenho

O Turbopack tornou-se estável no modo de desenvolvimento (next dev).

# Iniciar servidor de desenvolvimento com Turbopack habilitado
next dev --turbo

Resultados do Benchmark

Next.js 15 + Turbopack vs Webpack:

MétricaWebpackTurbopack
Inicialização do servidor local4,2s1,1s
Compilação inicial8,5s2,3s
Fast Refresh320ms45ms
Atualização de rota180ms25ms

※ Medições em aplicação de grande escala (1000+ componentes)

Status de Suporte

// Status atual de suporte do Turbopack
const turbopackSupport = {
  development: 'stable',      // Estável
  production: 'coming soon',  // Em breve
  features: {
    appRouter: 'full',
    pagesRouter: 'full',
    cssModules: 'full',
    tailwindCSS: 'full',
    sassScss: 'full',
    mdx: 'full',
    nextImage: 'full',
    nextFont: 'full',
  },
};

Pré-renderização Parcial (PPR)

Combinação Ideal de Estático e Dinâmico

PPR é uma funcionalidade experimental que combina eficientemente partes estáticas e dinâmicas na mesma página.

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  experimental: {
    ppr: 'incremental',  // Habilitar por rota
  },
};

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>
      {/* Pré-renderizado estaticamente */}
      <StaticHeader />

      {/* Streaming dinâmico */}
      <Suspense fallback={<LoadingSkeleton />}>
        <DynamicContent />
      </Suspense>
    </div>
  );
}

Fluxo de Funcionamento do PPR

flowchart TB
    subgraph BuildTime["Tempo de Build"]
        StaticShell["Shell Estático<br/>(Header, Layout, Fallback)<br/>→ Pré-gerado como HTML"]
    end

    subgraph RequestTime["Tempo de Requisição"]
        Step1["1. Retorna shell estático imediatamente (TTFB minimizado)"]
        Step2["2. Streaming de conteúdo dinâmico"]
        Step3["3. Hidratação progressiva nos boundaries do Suspense"]
        Step1 --> Step2 --> Step3
    end

    BuildTime --> RequestTime

API next/after

Execução de Processamento Após a Resposta

next/after é uma nova API que permite executar processamento após retornar a resposta ao cliente.

// app/api/submit/route.ts
import { after } from 'next/server';

export async function POST(request: Request) {
  const data = await request.json();

  // Retorna resposta imediatamente
  const result = await processSubmission(data);

  // Processamento em background após a resposta
  after(async () => {
    await sendEmailNotification(data.email);
    await logAnalytics('form_submitted', data);
    await updateSearchIndex(result.id);
  });

  return Response.json({ success: true, id: result.id });
}
// Uso em Server Component
import { after } from 'next/server';

export default async function Page() {
  const data = await fetchData();

  // Executar após renderização da página
  after(() => {
    logPageView('/dashboard');
  });

  return <Dashboard data={data} />;
}

Casos de Uso

  • Envio de analytics
  • Registro de logs
  • Aquecimento de cache
  • Envio de notificações
  • Atualização de índice de busca

Mudanças no Comportamento do Cache

Mudança no Comportamento Padrão (Mudança Quebrada)

No Next.js 15, o comportamento padrão do cache foi significativamente alterado.

// Next.js 14 e anteriores
fetch('https://api.example.com/data');
// Padrão: force-cache (com cache)

// Next.js 15
fetch('https://api.example.com/data');
// Padrão: no-store (sem cache)

Especificação Explícita de Cache

// Especificar explicitamente para habilitar o cache
fetch('https://api.example.com/data', {
  cache: 'force-cache',
});

// Ou especificar revalidate
fetch('https://api.example.com/data', {
  next: { revalidate: 3600 },  // 1 hora
});

Cache do Route Handler

// app/api/data/route.ts

// Next.js 14: GET era cacheado por padrão
// Next.js 15: Sem cache por padrão

export async function GET() {
  const data = await fetchData();
  return Response.json(data);
}

// Para tornar estático
export const dynamic = 'force-static';

// Ou especificar revalidate
export const revalidate = 3600;

Client Router Cache

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  experimental: {
    staleTimes: {
      dynamic: 30,   // Tempo de cache para páginas dinâmicas (segundos)
      static: 180,   // Tempo de cache para páginas estáticas (segundos)
    },
  },
};

Estabilização da API de Instrumentação

Bootstrap da Aplicação

// instrumentation.ts (raiz do projeto)
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    // Executar apenas no runtime Node.js
    const { initializeDatabase } = await import('./lib/db');
    await initializeDatabase();

    const { startMetricsCollection } = await import('./lib/metrics');
    startMetricsCollection();
  }

  if (process.env.NEXT_RUNTIME === 'edge') {
    // Inicialização no runtime Edge
    console.log('Runtime Edge inicializado');
  }
}

export async function onRequestError(
  err: Error,
  request: Request,
  context: { routerKind: string; routePath: string }
) {
  // Rastreamento de erros
  await reportError(err, {
    url: request.url,
    ...context,
  });
}

Melhorias na Experiência de Desenvolvimento

Melhoria na Exibição de Erros

flowchart TB
    subgraph ErrorUI["Melhoria na UI de Erros do Next.js 15"]
        Error["Error: Cannot read properties of undefined"]

        subgraph SourceCode["Código Fonte"]
            Line12["12 │ const user = await getUser(id);"]
            Line13["13 │ return user.name; ← Local do erro"]
            Line14["14 │ }"]
        end

        subgraph StackTrace["Stack Trace"]
            ST1["app/dashboard/page.tsx:13"]
            ST2["..."]
        end

        Actions["[Ver documentação] [Reportar Issue]"]

        Error --> SourceCode --> StackTrace --> Actions
    end

Static Indicator

Permite verificar visualmente a renderização estática/dinâmica durante o desenvolvimento.

// Páginas estáticas mostram indicador verde
// Páginas dinâmicas mostram indicador azul
// exibido no canto inferior direito do navegador

Como Fazer o Upgrade

Upgrade Automático

# Upgrade automático usando codemod
npx @next/codemod@canary upgrade latest

Upgrade Manual

# Atualizar dependências
npm install next@latest react@rc react-dom@rc

# Para TypeScript
npm install @types/react@rc @types/react-dom@rc

Principais Trabalhos de Migração

// 1. Comportamento de cache do fetch
// Antes (Next.js 14)
fetch('/api/data');  // Com cache

// Depois (Next.js 15)
fetch('/api/data', { cache: 'force-cache' });  // Especificar explicitamente

// 2. Route Handler
// Antes
export async function GET() { ... }  // Cache automático

// Depois
export const dynamic = 'force-static';  // Tornar estático explicitamente
export async function GET() { ... }

// 3. Importação de Server Actions
// Antes
'use server';
// Arquivo inteiro são Server Actions

// Depois (recomendado)
// Separar em actions.ts e importar
import { submitForm } from './actions';

Nova Estrutura de Projeto (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   # Novo
├── next.config.ts       # De .mjs para .ts
└── package.json

Dicas de Otimização de Desempenho

1. Aproveitar o Turbopack

// package.json
{
  "scripts": {
    "dev": "next dev --turbo",
    "build": "next build",
    "start": "next start"
  }
}

2. Introdução Gradual do PPR

// Habilitar sequencialmente a partir de páginas de alto tráfego
export const experimental_ppr = true;

3. Estratégia de Cache Adequada

// Configuração de cache conforme a natureza dos dados
const staticData = await fetch('/api/config', {
  cache: 'force-cache',
});

const userData = await fetch('/api/user', {
  cache: 'no-store',  // Sempre atual
});

const productData = await fetch('/api/products', {
  next: { revalidate: 60 },  // Atualizar a cada 1 minuto
});

Resumo

O Next.js 15 alcançou uma grande evolução tanto em desempenho quanto em experiência de desenvolvimento.

Principais Pontos de Upgrade

  1. Suporte ao React 19: Novos hooks, melhorias nas Server Actions
  2. Turbopack estável: Velocidade de build drasticamente melhorada no desenvolvimento
  3. PPR: Combinação ideal de estático e dinâmico
  4. Mudança de cache: Comportamento padrão mais previsível

Pontos de Atenção na Migração

  • Comportamento de cache do fetch mudou para no-store por padrão
  • Cache do Route Handler também foi alterado da mesma forma
  • Migração gradual usando codemod é recomendada

Com a combinação do React 19, o Next.js se tornou ainda mais poderoso como framework React full-stack.

← Voltar para a lista