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
| Funcionalidade | Status | Impacto |
|---|---|---|
| Suporte ao React 19 | Estável | Alto |
| Turbopack Dev | Estável | Alto |
| Pré-renderização Parcial (PPR) | Experimental | Médio |
| API next/after | Estável | Médio |
| Mudanças no comportamento do cache | Mudança quebrada | Alto |
| Suporte ao ESLint 9 | Estável | Baixo |
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étrica | Webpack | Turbopack |
|---|---|---|
| Inicialização do servidor local | 4,2s | 1,1s |
| Compilação inicial | 8,5s | 2,3s |
| Fast Refresh | 320ms | 45ms |
| Atualização de rota | 180ms | 25ms |
※ 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
- Suporte ao React 19: Novos hooks, melhorias nas Server Actions
- Turbopack estável: Velocidade de build drasticamente melhorada no desenvolvimento
- PPR: Combinação ideal de estático e dinâmico
- 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.