Next.js 16: o que quebra na migração
São 21 mudanças que quebram e o codemod oficial cobre cinco. O resto derruba o build sem aviso — incluindo uma que atinge quem usa scroll suave.
- next.js
- migração

Sumário
- Antes de começar: os mínimos
- O que o codemod resolve, e o que não
- Turbopack por padrão: seu build pode falhar de propósito
- Async Request APIs: acabou o período de graça
- middleware virou proxy — e o edge ficou para trás
- Cache: assinatura nova e uma flag que não é rename
- next/image: seis defaults mudaram
- O que foi removido de vez
- Três mudanças de tooling que passam despercebidas
- A mudança de scroll que quase ninguém viu
- O caminho que a Vercel recomenda: migrar com agente
- A ordem que eu seguiria
- Perguntas frequentes
- Fontes
O codemod oficial resolve cinco coisas. As outras dezesseis você faz na mão, e várias derrubam o build sem dar pista do motivo.
Não é uma atualização de rotina. O Next.js 16 encerrou o período de compatibilidade que a 15 tinha aberto, trocou o bundler padrão, renomeou o middleware, mudou seis defaults do next/image e removeu APIs que existiam desde sempre.
Este é o mapa do que quebra, na ordem em que você vai encontrar cada coisa.
Antes de começar: os mínimos
Três barreiras que param a instalação antes de qualquer código:
| Requisito | Mudança |
|---|---|
| Node.js | Mínimo 20.9.0 (LTS). Node 18 não é mais suportado |
| TypeScript | Mínimo 5.1.0 |
| Browsers | Chrome 111+, Edge 111+, Firefox 111+, Safari 16.4+ |
Se o seu deploy roda em Node 18, resolva isso primeiro — nada mais importa até lá. Quem segue a documentação de deploy com GitHub e Hostinger precisa conferir a versão de Node no painel antes de dar push.
O que o codemod resolve, e o que não
Comece por ele:
npx @next/codemod@canary upgrade latestEle cobre exatamente cinco coisas: atualiza o next.config.js para a configuração nova do Turbopack, migra de next lint para o ESLint CLI, renomeia middleware para proxy, tira o prefixo unstable_ das APIs estabilizadas e remove o experimental_ppr de páginas e layouts.
O upgrade não roda todas as migrações. Se o seu app ainda usa acesso síncrono a Request APIs, rode também:
npx @next/codemod@canary next-async-request-api .E se você usava next lint, há um terceiro:
npx @next/codemod@canary next-lint-to-eslint-cli .Tudo que não está nessas três listas é trabalho manual.
Turbopack por padrão: seu build pode falhar de propósito
A partir da 16, o Turbopack é estável e usado por padrão em next dev e next build. Os flags --turbopack e --turbo viraram desnecessários.
O problema aparece em projeto com configuração de webpack: o build falha, deliberadamente, para evitar erro de configuração silencioso. Três saídas:
{
"scripts": {
"dev": "next dev",
"build": "next build --webpack"
}
}Usar --webpack mantém o comportamento antigo no build. Alternativamente, next build --turbopack ignora sua config de webpack, ou você migra a config para o equivalente em Turbopack.
Uma armadilha comum: se o build falha reclamando de config de webpack e você não escreveu nenhuma, provavelmente um plugin está injetando a opção.
Duas mudanças menores que pegam: a configuração saiu de experimental.turbopack para turbopack no topo do nextConfig, e o Turbopack não suporta o til (~) do Sass. @import '~bootstrap/...' vira @import 'bootstrap/...'.
Async Request APIs: acabou o período de graça
A versão 15 introduziu as Request APIs assíncronas com compatibilidade síncrona temporária. Na 16, o acesso síncrono foi removido.
Vale para cookies(), headers(), draftMode(), params em layout, page, route, default, opengraph-image, twitter-image, icon e apple-icon, e searchParams em page.
Há um detalhe que o codemod não cobre e que pega quem gera imagem dinâmica: nas funções de opengraph-image, twitter-image, icon e apple-icon, o id também virou Promise:
// Next.js 16
export default async function Image({ params, id }) {
const { slug } = await params
const imageId = await id // agora é Promise<string>
}O mesmo aconteceu com o id do sitemap. E note a assimetria: o generateImageMetadata continua recebendo params síncrono.
Para migrar com tipagem, npx next typegen gera os helpers PageProps, LayoutProps e RouteContext:
export default async function Page(props: PageProps<'/blog/[slug]'>) {
const { slug } = await props.params
}middleware virou proxy — e o edge ficou para trás
O arquivo middleware foi renomeado para proxy, para deixar clara a fronteira de rede. O export nomeado também muda:
// proxy.ts
export function proxy(request: Request) {}Flags de configuração acompanham: skipMiddlewareUrlNormalize virou skipProxyUrlNormalize.
A pegadinha que o rename esconde: o proxy não suporta o edge runtime. Ele roda em nodejs, e isso não é configurável. Quem depende de edge precisa continuar no middleware — a documentação promete instruções em release menor.
Ou seja: o rename esconde uma decisão de arquitetura, e o codemod vai renomear seu arquivo sem perguntar se você usa edge.
Cache: assinatura nova e uma flag que não é rename
Duas mudanças independentes, fáceis de confundir.
revalidateTag agora exige um segundo argumento com o perfil de cacheLife. A forma de um argumento está depreciada e produz erro de TypeScript:
revalidateTag('posts') // antes
revalidateTag('posts', 'max') // agoraSe você precisa de expiração imediata em vez de stale-while-revalidate, existe a API nova updateTag, exclusiva de Server Actions, com semântica de read-your-own-writes: o usuário faz a mudança e vê o resultado na hora. Chamar fora de Server Action lança erro — em Route Handler e webhook, use revalidateTag com perfil.
Também estabilizaram cacheLife e cacheTag. Os imports com unstable_ podem cair.
A segunda mudança é maior do que parece. O flag experimental de Partial Prerendering saiu, junto com experimental.dynamicIO, experimental.useCache e o segment config experimental_ppr. O substituto é cacheComponents: true — e a documentação avisa que não é uma troca de nome:
Com a flag ligada, os route segment configs dynamic, revalidate e fetchCache passam a dar erro, substituídos por use cache e cacheLife. E há um detalhe que trava build sem escapatória: chamadas de IO síncrono no prerender (new Date(), Date.now(), Math.random(), crypto.randomUUID()) falham o build e não podem ser adiadas nem com a opção de escape instant = false.
Se você usa PPR hoje, a recomendação oficial é permanecer no canary da 15 que você já usa.
next/image: seis defaults mudaram
Nenhum quebra o build. Todos mudam o comportamento em produção.
| Configuração | Antes | Agora |
|---|---|---|
minimumCacheTTL | 60 segundos | 4 horas (14400s) |
imageSizes | incluía 16 | 16 removido do array padrão |
qualities | todas permitidas | só [75] |
maximumRedirects | ilimitado | 3 |
| IP local | permitido | bloqueado, salvo dangerouslyAllowLocalIP |
| Query string local | livre | exige images.localPatterns.search |
A de qualities é a que mais surpreende: se você passa quality={90}, o valor é coagido para o mais próximo da lista — ou seja, 75. Sua imagem fica com qualidade diferente da que você pediu, sem erro nenhum.
Além disso, next/legacy/image está depreciado e images.domains também — a substituição é images.remotePatterns.
O que foi removido de vez
| Removido | Substituto |
|---|---|
Suporte a AMP (next/amp, useAmp, amp config) | Nenhum |
Comando next lint | Biome ou ESLint direto. next build não roda mais lint |
serverRuntimeConfig e publicRuntimeConfig | Variáveis de ambiente, com NEXT_PUBLIC_ para o cliente |
devIndicators.appIsrStatus, buildActivity, buildActivityPosition | O indicador em si continua |
unstable_rootParams | next/root-params |
Duas mudanças estruturais no mesmo pacote: rotas paralelas agora exigem default.js explícito em cada slot, e sem ele o build falha; e o next build deixou de reportar as métricas size e First Load JS, porque a própria equipe as considerou imprecisas em arquitetura com Server Components.
Três mudanças de tooling que passam despercebidas
ESLint mudou de formato. O @next/eslint-plugin-next agora usa Flat Config por padrão, alinhado com o ESLint v10, que vai abandonar o formato legado. Se você ainda está no .eslintrc, a migração virou item de fila.
dev e build rodam ao mesmo tempo. Os dois passaram a usar diretórios de saída separados (o next dev escreve em .next/dev), e um lockfile impede duas instâncias do mesmo comando no mesmo projeto. Na prática, dá para deixar o dev server rodando enquanto valida um build.
process.argv não contém mais 'dev'. Antes, o arquivo de config era carregado duas vezes em desenvolvimento: no comando e no servidor. Agora carrega uma vez só, e a consequência é que checar process.argv.includes('dev') dentro do next.config retorna false.
Isso quebra plugin que dispara efeito colateral em desenvolvimento. A troca é direta:
// Antes — não funciona mais
const isDev = process.argv.includes('dev')
// Agora
const isDev = process.env.NODE_ENV === 'development'Os comandos typegen e build continuam visíveis no process.argv. Só o dev sumiu.
A mudança de scroll que quase ninguém viu
Esta não aparece em lista de destaque e atinge todo site com motion.
Nas versões anteriores, se você tinha scroll-behavior: smooth no <html>, o Next.js sobrescrevia isso durante transição de rota: trocava para auto, navegava com salto instantâneo ao topo, e devolvia o valor original. Era o que mantinha a navegação entre páginas sensação de instantânea mesmo com scroll suave ativo.
Na 16, esse override acabou. O Next.js respeita o seu scroll-behavior.
O efeito prático: quem tem smooth scroll global vai ver a navegação de rota virar uma rolagem animada até o topo, em vez do salto seco. Em página longa, isso é perceptível e pode parecer bug.
Para recuperar o comportamento antigo, o opt-in é um atributo:
export default function RootLayout({ children }) {
return (
<html lang="pt-BR" data-scroll-behavior="smooth">
<body>{children}</body>
</html>
)
}Se o seu site depende de scroll suave, o catálogo de técnicas de motion para web cobre as alternativas.
Vale checar junto: se você habilitar cacheComponents, as rotas passam a ser preservadas com o <Activity> do React em modo oculto em vez de desmontadas. Isso significa que useState, valores de formulário e posição de scroll deixam de resetar ao navegar e voltar. Dropdown continua aberto, diálogo não refaz o efeito de foco, formulário mantém o resultado do submit.
O caminho que a Vercel recomenda: migrar com agente
A primeira seção do guia oficial de upgrade se chama "Use an AI agent (recommended)", e traz um prompt pronto para colar.
Isso não é marketing solto. A partir da 16.3, rodar next dev com um agente detectado no ambiente gera automaticamente AGENTS.md e CLAUDE.md na raiz do projeto. O CLAUDE.md gerado é literalmente uma linha:
@AGENTS.mdE o bloco gerenciado dentro do AGENTS.md abre com um aviso que vale ler:
O framework agora empacota a própria documentação dentro do pacote next, em node_modules/next/dist/docs/, com versão casada. Atualizar o Next.js atualiza os docs que o agente lê. Para desligar, agentRules: false.
Há uma afirmação nesse guia que interessa a quem monta setup de agente:
É a primeira medição pública que vi sobre esse trade-off, e ela contraria a intuição de "mova tudo para skill e deixe o contexto leve". Para conhecimento que o agente precisa em toda tarefa, a Vercel mediu que carregar sempre vence.
Vale ler junto com a anatomia de um CLAUDE.md que funciona: as duas fontes chegam ao mesmo lugar por caminhos opostos.
Também vale saber que existe um servidor MCP embutido em /_next/mcp, expondo rotas, logs e problemas de compilação do dev server, e uma skill oficial next-dev-loop para o ciclo de editar e verificar — ela entra na mesma categoria das que reuni no catálogo de skills avaliadas.
A ordem que eu seguiria
- Node 20.9 e TypeScript 5.1 no ambiente e no CI. Antes de tudo.
- Rode os três codemods —
upgrade,next-async-request-api,next-lint-to-eslint-cli. - Decida sobre o Turbopack antes de rodar o build. Se tem config de webpack, escolha entre migrar ou
--webpack. - Verifique o edge antes de aceitar o rename de
proxy. É a decisão menos reversível da lista. next builde resolva o que aparecer. Rotas paralelas semdefault.jsaparecem aqui.- Confira as seis mudanças do
next/imageem produção — nenhuma quebra o build, todas mudam o resultado. - Teste a navegação com scroll suave, se você usa.
cacheComponentsfica para depois. É migração própria, não parte desta.
Os passos 1 a 5 são a migração. Os 6 a 8 são o que você descobre em produção se pular.
Perguntas frequentes
Dá para migrar sem adotar Cache Components?
Dá, e é o recomendado. cacheComponents é opcional na 16 e representa uma migração separada, com modelo de cache próprio. Se você usava experimental.dynamicIO ou experimental.useCache, remova os flags. Se usa PPR experimental hoje, a orientação oficial é ficar no canary da 15 até planejar a adoção.
O codemod é seguro para rodar direto na main?
Rode em branch. Ele renomeia arquivos, mexe no next.config e altera imports — e o rename de middleware para proxy é o caso mais delicado, porque muda o runtime disponível sem avisar.
Meu build falha reclamando de webpack e eu não uso webpack. Por quê?
Quase sempre é um plugin injetando a opção webpack na config. A documentação cita isso explicitamente. Ou você identifica o plugin, ou passa --webpack no build.
Preciso mesmo usar agente para migrar?
Não. O guia oferece o caminho manual completo. Mas se você já usa Claude Code ou Codex, vale rodar o next dev na 16.3+ só para ver o AGENTS.md sendo gerado — os docs empacotados por versão resolvem o problema de o agente responder com API da versão 14.
Fontes
- Next.js — How to upgrade to version 16. Versão 16.3.1, doc atualizada em 18/08/2026. Acesso em 20/08/2026.
- Next.js — Migrating to Cache Components. Doc atualizada em 07/08/2026. Acesso em 20/08/2026.
- Next.js — How to set up your Next.js project for AI coding agents. Doc atualizada em 05/08/2026. Acesso em 20/08/2026.
Verificado em 20 de agosto de 2026.
Gatilho de reavaliação: revisar quando (a) sair a release menor com as instruções de edge runtime para proxy, (b) cacheComponents deixar de ser opcional, (c) os defaults do next/image mudarem de novo, ou (d) a geração automática de AGENTS.md mudar de comportamento.
Leia também
Motion •
View Transitions no Next.js 16: as três camadas
Uma é Baseline, outra não roda no Firefox e a terceira é experimental no React. Saber qual você está usando decide o que vai para produção.
- next.js
- react
Motions premium em Next.js: os 18 padrões do site da Plantica, passo a passo
O scroll vira CSS custom property e o CSS faz o resto: os 18 padrões de motion do site da Plantica em Next.js, com o prompt de implementação pronto de cada um.
- motion
- gsap
Motions premium em Next.js: os 18 padrões do site da ANAI, passo a passo
A arquitetura híbrida do site da ANAI — CSS vars, tweens por seção e canvas — destrinchada em 18 padrões de motion com prompts prontos.
- motion
- gsap


