Capítulo 94 de 456

Version 15

Core Idea

Guia de upgrade de Next.js 14 para 15 — a versão que tornou cookies(), headers(), draftMode(), params e searchParams assíncronos, mudou defaults de cache de fetch/Route Handlers/Client Cache, e exige React 19.

Key Concepts

  • Codemod upgrade: npx @next/codemod@canary upgrade latest automatiza a maior parte da migração, incluindo as Async Request APIs.
  • React 19 mínimo: useFormState foi substituído por useActionState (ainda disponível mas deprecated); useFormStatus ganhou chaves extras (data, method, action).
  • Async Request APIs (breaking change): cookies(), headers(), draftMode(), params (em layout/page/route/default/opengraph-image/twitter-image/icon/apple-icon) e searchParams (em page) passam de síncronos para assíncronos.
  • Uso síncrono temporário: cookies() as unknown as UnsafeUnwrappedCookies (e equivalentes para headers/draftMode) — funciona mas loga warning em dev; é ponte de migração, não solução definitiva.
  • runtime: 'experimental-edge' removido: agora gera erro; usar runtime: 'edge'.
  • fetch não cacheado por padrão: era cacheado por padrão antes; agora precisa cache: 'force-cache' explícito por request, ou export const fetchCache = 'default-cache' no segmento para aplicar a todos os fetches que não especificam cache próprio.
  • Route Handlers GET não cacheados por padrão: usar export const dynamic = 'force-static' para opt-in.
  • Client Cache de páginas não reutiliza segmentos por padrão: reuso ainda ocorre em navegação back/forward do browser e em layouts compartilhados; configurável via staleTimes (dynamic/static) em next.config.js.
  • bundlePagesRouterDependencies: renomeação estável de experimental.bundlePagesExternals.
  • serverExternalPackages: renomeação estável de experimental.serverComponentsExternalPackages.
  • geo/ip removidos de NextRequest: use geolocation/ipAddress de @vercel/functions (codemod next-request-geo-ip disponível).

Code Examples

import { cookies } from 'next/headers'

// Before
const cookieStore = cookies()
const token = cookieStore.get('token')

// After
const cookieStore = await cookies()
const token = cookieStore.get('token')
  • O que demonstra: forma recomendada de migrar cookies() para assíncrono.
// After
import { use } from 'react'

type Params = Promise<{ slug: string }>

export default function Layout(props: { children: React.ReactNode; params: Params }) {
  const params = use(props.params)
  const slug = params.slug
}
  • O que demonstra: em componente síncrono, usar use() do React para desembrulhar params (agora uma Promise) em vez de await.
export const fetchCache = 'default-cache'

export default async function RootLayout() {
  const a = await fetch('https://...') // Cached
  const b = await fetch('https://...', { cache: 'no-store' }) // Not cached
}
  • O que demonstra: reverter o novo default de "não cacheado" para todos os fetches do segmento, exceto os que especificam cache próprio.
const nextConfig = {
  experimental: {
    staleTimes: { dynamic: 30, static: 180 },
  },
}
  • O que demonstra: reabilitar reuso de segmentos de página no Client Cache via staleTimes.

Anti-patterns

  • Manter o uso síncrono temporário (UnsafeUnwrappedCookies etc.) como solução permanente: gera warning em dev e é só ponte de migração — migre para await/use().
  • Assumir que fetch ainda é cacheado por padrão como na v14: mudança silenciosa de comportamento pode gerar dados desatualizados sendo tratados como sempre frescos, ou o oposto (perda de cache esperado).
  • Depender de geo/ip de NextRequest: removidos; migrar para @vercel/functions ou provedor equivalente.

Key Takeaways

  1. O upgrade automatizado via codemod cobre a maior parte da migração das Async Request APIs — prefira rodá-lo a fazer manualmente.
  2. Três defaults de cache mudaram simultaneamente na v15: fetch, Route Handlers GET, e Client Cache de páginas — todos passam de "cacheado" para "não cacheado" por padrão.
  3. runtime = 'experimental-edge' virou erro rígido; só edge é aceito.

Connects To

  • Codemods (ch092): next-async-request-api, app-dir-runtime-config-experimental-edge e next-request-geo-ip automatizam partes desta migração.
  • Version 14 (ch093): versão de origem deste upgrade.
  • Version 16 (ch095): próxima major version.