Extração de Payload no Nuxt 4: navegação mais rápida sem chamadas extras à API cover image

Extração de Payload no Nuxt 4: navegação mais rápida sem chamadas extras à API

Se você já colocou em produção uma aplicação Nuxt com renderização no servidor, provavelmente já se beneficiou do sistema de payload sem perceber. Durante o SSR, os dados buscados com useAsyncData e useFetch são serializados e enviados ao navegador para que a hidratação não dispare requisições duplicadas. Esse mecanismo mantém a primeira renderização rápida e evita o clássico problema de “buscar duas vezes”.

A extração de payload leva essa ideia um passo além. Em vez de manter todos os dados serializados dentro do HTML, o Nuxt pode gravar um arquivo separado _payload.json ao lado de cada página pré-renderizada ou em cache. Quando o usuário navega no cliente até essa rota, o framework carrega o payload em cache diretamente. Seus componentes continuam hidratando com os mesmos dados, mas o backend recebe bem menos chamadas repetidas.

O que existe dentro de um arquivo de payload?

O payload do Nuxt é um objeto JavaScript exposto por useNuxtApp().payload. Ele armazena os resultados dos composables assíncronos, indexados pela chave que você passa ao useAsyncData ou pela chave gerada automaticamente pelo useFetch. O Nuxt serializa esses dados com devalue, o que significa que você não fica limitado a JSON puro. Dates, Maps, Sets, refs reativas e instâncias de NuxtError podem atravessar a transferência do servidor para o cliente quando configurados corretamente.

Em uma página de produto pré-renderizada, por exemplo, o HTML pode conter apenas a marcação e o código mínimo de inicialização, enquanto /products/widget/_payload.json guarda o registro do catálogo, itens relacionados e qualquer outro estado assíncrono resolvido durante a renderização. A navegação no cliente entre páginas em cache fica mais próxima de carregar assets estáticos do que de executar novamente sua camada de dados.

Por que a extração de payload importa em produção

Manter o payload inline no HTML funciona, mas tem trade-offs. Conjuntos grandes de dados incham o HTML, aumentam o Time to First Byte em requisições frias e reduzem a eficiência de cache, porque HTML e dados compartilham o mesmo documento. Extrair o payload para um arquivo dedicado traz três ganhos práticos:

  • Respostas HTML menores na carga inicial quando você escolhe o modo de extração client.
  • Cache amigável a CDN, já que o _payload.json pode ser cacheado junto com o HTML na Vercel, Netlify, Cloudflare e outras plataformas de edge.
  • Menos chamadas à API durante navegação estilo SPA, o que faz diferença em sites ISR, SWR e estáticos com layouts compartilhados e fetches globais.

Para sites com muito conteúdo, páginas de marketing e catálogos de e-commerce, essa combinação costuma aparecer como menos tráfego na origem e transições mais fluidas entre rotas.

Onde o Nuxt 4 gera arquivos de payload

A extração de payload não é mais exclusividade do nuxt generate. No Nuxt 4, especialmente a partir da v4.3, os arquivos _payload.json são produzidos para:

  • Rotas pré-renderizadas no momento do build
  • Rotas ISR na primeira requisição, com regeneração conforme a janela de revalidação
  • Rotas SWR que servem conteúdo stale enquanto atualizam em segundo plano
  • Regras de cache configuradas via Nitro

Essa expansão é importante para projetos reais. Uma rota dinâmica como pages/blog/[slug].vue não precisa de um caminho em build time para cada artigo se você aplicar uma regra como /blog/**: { isr: 3600 }. O primeiro visitante dispara a renderização, e o Nuxt persiste HTML e payload para navegações futuras.

Configurando o payloadExtraction

O comportamento é controlado por experimental.payloadExtraction no nuxt.config.ts. O Nuxt oferece três modos:

  • true — o payload é extraído para _payload.json tanto na renderização inicial quanto na navegação no cliente. Esse é o padrão atual no Nuxt 4.
  • 'client' — o payload permanece inline no HTML na primeira requisição, mas arquivos separados são gerados para navegações subsequentes no cliente. Isso evita uma ida extra à rede na carga inicial, preservando transições rápidas depois. Projetos que miram compatibilidade com Nuxt 5 costumam tratar esse modo como padrão preferido.
  • false — a extração é desativada. O payload fica inline no HTML e nenhum _payload.json é criado.

Uma configuração típica para uma loja híbrida pode ficar assim:

export default defineNuxtConfig({
  experimental: {
    payloadExtraction: 'client',
  },
  routeRules: {
    '/': { prerender: true },
    '/products/**': { isr: 3600 },
    '/blog/**': { swr: true },
  },
})

Com essa configuração, a home fica totalmente estática, as páginas de produto revalidam a cada hora e os posts do blog podem servir conteúdo em cache imediatamente enquanto atualizam de forma assíncrona. Em todos os casos, as navegações podem reutilizar o payload extraído em vez de buscar novamente na sua API Laravel ou Node.

Combinando route rules com busca de dados

A extração de payload só ajuda quando suas páginas realmente populam o payload durante a renderização. Isso significa usar useAsyncData ou useFetch no setup, e não chamadas isoladas de $fetch que ignoram o pipeline de payload.

Veja uma página de artigo:

const route = useRoute()

const { data: article } = await useAsyncData(
  `article-${route.params.slug}`,
  () => $fetch(`/api/articles/${route.params.slug}`),
)

const { data: related } = await useAsyncData(
  `related-${route.params.slug}`,
  () => $fetch(`/api/articles/${route.params.slug}/related`),
)

Quando a página é pré-renderizada ou cacheada via ISR, os dois conjuntos de dados são serializados. Em uma navegação posterior de /blog para /blog/meu-post, o Nuxt pode hidratar a partir do _payload.json em vez de fazer duas novas requisições à API. Se você tivesse usado apenas $fetch no onMounted, perderia essa otimização por completo.

Chaves, sharedPrerenderData e uma armadilha comum

A extração de payload funciona melhor quando as chaves são previsíveis e únicas. No Nuxt 4, sharedPrerenderData vem habilitado por padrão na geração estática. Durante o prerender, o Nuxt pode reutilizar entradas de payload entre páginas quando a mesma chave resolve para os mesmos dados. Isso acelera muito builds de sites grandes.

O risco aparece em rotas dinâmicas. Se você omitir uma chave explícita, o Nuxt pode gerar uma com base no arquivo, o que pode colidir entre páginas que buscam registros diferentes. O padrão seguro é incluir parâmetros de rota ou identificadores de entidade na chave:

// Inseguro em [slug].vue porque a chave ignora o slug
await useAsyncData(() => $fetch(`/api/pages/${route.params.slug}`))

// Seguro: a chave reflete o recurso buscado
await useAsyncData(route.params.slug, () =>
  $fetch(`/api/pages/${route.params.slug}`),
)

Isso importa em dois momentos: na deduplicação em build time e quando uma CDN serve arquivos de payload em cache para usuários reais. Uma chave errada pode causar vazamento de dados entre páginas, algo difícil de perceber no ambiente local.

Depurando o comportamento do payload em desenvolvimento

A extração de payload costumava ser verificada só depois de um build de produção. No Nuxt 4, ela também funciona em desenvolvimento quando nitro.static está habilitado ou quando a rota usa regras de prerender, isr, swr ou cache. Isso facilita muito confirmar a geração dos arquivos antes do deploy.

Verificações práticas:

  • Execute nuxt generate ou um build de produção com regras de prerender e inspecione .output/public em busca de arquivos _payload.json.
  • Abra a aba Network do DevTools durante navegação no cliente e observe requisições de payload em vez de chamadas duplicadas à API.
  • Inspecione window.__NUXT__ na carga inicial e compare o que muda após navegar para uma rota em cache.
  • Sobrescreva getCachedData apenas quando houver uma estratégia de cache deliberada; o padrão já lê dos stores de payload e static.

Quando desativar ou mudar o modo

A extração de payload não é obrigatória para todo app. Mantenha o payload inline com payloadExtraction: false quando:

  • Suas páginas são majoritariamente renderizadas no cliente e nunca são pré-renderizadas ou cacheadas.
  • Os arquivos de payload conteriam dados altamente específicos do usuário, que não devem ser cacheados na borda da CDN.
  • Você está depurando inconsistências de hidratação e quer menos variáveis no meio do caminho.

Escolha 'client' quando a performance da primeira carga importa mais do que separar HTML e dados na requisição inicial. Mantenha true quando quiser granularidade máxima de cache para HTML e payload em todas as navegações.

Considerações finais

A extração de payload é um daqueles recursos do Nuxt que recompensa times que já pensam em modos de renderização. Se você combina routeRules, chaves consistentes no useAsyncData e o modo certo de payloadExtraction, obtém velocidade de site estático com o conforto de navegação SPA. O detalhe de implementação é um arquivo JSON ao lado do HTML. O resultado são menos chamadas à API, melhor aproveitamento da CDN e uma experiência visivelmente mais fluida para quem percorre páginas pré-renderizadas ou em cache.