Nuxt 4 em 2026: nova estrutura de diretórios e migração do Nuxt 3

Guia completo de migração para o Nuxt 4: estrutura de diretórios app/, camada singleton de busca de dados, melhorias no TypeScript e instruções passo a passo com exemplos de código.

Nuxt 4 nova estrutura de diretórios e migração do Nuxt 3

O Nuxt 4 introduz uma estrutura de diretórios redesenhada que separa o código da aplicação da configuração, acompanhada de uma camada singleton de busca de dados, reatividade superficial por padrão e contextos TypeScript divididos. Lançado em julho de 2025 e atualmente na versão 4.4, essa atualização major prioriza a evolução ao invés da revolução, tornando o caminho de migração do Nuxt 3 consideravelmente mais suave do que a transição do Nuxt 2 para o 3.

Migração automatizada disponível

A equipe do Nuxt firmou parceria com o Codemod para automatizar a maioria dos passos da migração. Basta executar npx codemod@latest nuxt/4/migration-recipe para lidar com a reestruturação de diretórios, atualizações de busca de dados e substituição de APIs obsoletas automaticamente.

A nova estrutura do diretório app/ no Nuxt 4

O Nuxt 4 move todo o código-fonte da aplicação para um diretório app/ por padrão. Essa separação resolve um problema real: os observadores de arquivos no Linux e Windows têm um desempenho significativamente melhor quando o código da aplicação fica em um subdiretório dedicado, em vez de misturado com node_modules/, .git/ e arquivos de configuração.

A nova organização segue esta estrutura:

text
my-nuxt-app/
├─ app/
│  ├─ assets/
│  ├─ components/
│  ├─ composables/
│  ├─ layouts/
│  ├─ middleware/
│  ├─ pages/
│  ├─ plugins/
│  ├─ utils/
│  ├─ app.vue
│  ├─ app.config.ts
│  └─ error.vue
├─ content/
├─ public/
├─ shared/         # Novo: código compartilhado entre app e servidor
├─ server/
└─ nuxt.config.ts

O diretório shared/ é uma adição notável. Qualquer composable ou utilitário colocado em shared/ é auto-importado tanto na aplicação Vue quanto no servidor Nitro, eliminando a necessidade de importações manuais ao compartilhar schemas de validação, definições de tipos ou funções utilitárias entre os dois contextos.

Migração passo a passo do Nuxt 3 para o Nuxt 4

O processo de atualização começa com um único comando. O Nuxt detecta a estrutura plana existente e continua funcionando sem nenhuma alteração, permitindo que a migração aconteça de forma incremental.

bash
# Atualizar o Nuxt e deduplicar dependências
npx nuxt upgrade --dedupe

Após atualizar o pacote, é necessário mover os arquivos da aplicação para o diretório app/:

bash
# Automatizar a reestruturação de diretórios
npx codemod@latest nuxt/4/file-structure

Esse codemod move assets/, components/, composables/, layouts/, middleware/, pages/, plugins/, utils/, app.vue, error.vue e app.config.ts para dentro de app/. Arquivos que pertencem à raiz — nuxt.config.ts, server/, public/ e content/ — permanecem no lugar.

Para projetos que precisam adiar a reestruturação, o diretório fonte pode ser configurado explicitamente:

nuxt.config.tstypescript
export default defineNuxtConfig({
  srcDir: '.',
  dir: { app: 'app' },
})

Essa configuração instrui o Nuxt 4 a resolver os arquivos a partir da raiz do projeto, replicando exatamente o comportamento do Nuxt 3.

Camada singleton de busca de dados e chaves reativas

O Nuxt 4 muda fundamentalmente a forma como useAsyncData e useFetch gerenciam os dados. Múltiplos componentes chamando a mesma chave agora compartilham uma única referência reativa, em vez de manter cópias independentes.

app/composables/useProductData.tstypescript
export function useProductData(productId: string) {
  return useAsyncData(
    `product-${productId}`,
    () => $fetch(`/api/products/${productId}`),
    {
      getCachedData: (key, nuxtApp, ctx) => {
        // ctx.cause indica o motivo do fetch
        if (ctx.cause === 'refresh:manual') return undefined
        return nuxtApp.payload.data[key]
      },
    },
  )
}

Três mudanças se destacam nessa nova camada de dados:

  • Referências compartilhadas: chamar useProductData('abc') em dois componentes retorna as mesmas refs data, error e status. Atualizar uma atualiza ambas.
  • Limpeza automática: quando o último componente usando uma chave é desmontado, o Nuxt libera os dados associados da memória.
  • Chaves reativas: encapsular uma chave em um computed ou ref dispara automaticamente um novo fetch quando o valor muda.

O callback getCachedData agora recebe um objeto de contexto com uma propriedade cause ('initial', 'refresh:hook', 'refresh:manual' ou 'watch'), permitindo controle granular sobre quando servir dados em cache versus buscar dados atualizados.

Valores padrão alterados

As propriedades data e error de useAsyncData/useFetch agora têm undefined como valor padrão em vez de null. É necessário atualizar as verificações === null para === undefined ou utilizar uma comparação não estrita.

Reatividade superficial por padrão para melhor desempenho

O Nuxt 4 altera data de useAsyncData e useFetch para shallowRef em vez de ref. O Vue não rastreia mais recursivamente cada propriedade aninhada, o que oferece melhorias de desempenho mensuráveis para respostas de API com objetos profundamente aninhados ou arrays grandes.

app/pages/dashboard.vuetypescript
<script setup lang="ts">
// Os dados agora usam shallowRef por padrão
const { data: metrics } = await useFetch('/api/dashboard/metrics')

// A mutação direta de propriedades não ativa a reatividade
// metrics.value.visits = 100  // Não vai provocar re-render

// Substituir o valor inteiro para ativar as atualizações
metrics.value = { ...metrics.value, visits: 100 }

// Ou ativar a reatividade profunda para essa chamada específica
const { data: settings } = await useFetch('/api/settings', {
  deep: true,
})
</script>

Para a maioria das exibições somente leitura (dashboards, listagens de produtos, páginas de artigos), a reatividade superficial funciona sem nenhuma alteração de código. A opção deep: true continua disponível para formulários ou interfaces interativas que modificam propriedades aninhadas diretamente.

Pronto para mandar bem nas entrevistas de Vue.js / Nuxt.js?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

Separação de contextos TypeScript e segurança de tipos aprimorada

O Nuxt 4 gera configurações TypeScript separadas para cada contexto do projeto:

  • .nuxt/tsconfig.app.json — Código da aplicação Vue
  • .nuxt/tsconfig.server.json — Código do servidor Nitro
  • .nuxt/tsconfig.shared.json — Utilitários compartilhados
  • .nuxt/tsconfig.node.json — Configuração em tempo de build

Essa separação significa que o IDE não sugere mais APIs exclusivas do servidor no código do cliente, e vice-versa. Um único tsconfig.json na raiz do projeto referencia as quatro configurações:

json
{
  "files": [],
  "references": [
    { "path": "./.nuxt/tsconfig.app.json" },
    { "path": "./.nuxt/tsconfig.server.json" },
    { "path": "./.nuxt/tsconfig.shared.json" },
    { "path": "./.nuxt/tsconfig.node.json" }
  ]
}

A verificação de tipos no CI também muda. O comando vue-tsc agora requer a flag -b (modo build) para processar corretamente as referências de projeto:

bash
# Antes (Nuxt 3)
nuxt prepare && vue-tsc --noEmit

# Depois (Nuxt 4)
nuxt prepare && vue-tsc -b --noEmit

Outra mudança no TypeScript: compilerOptions.noUncheckedIndexedAccess está ativado por padrão (true). Acessar um elemento de array ou propriedade de objeto por índice agora retorna T | undefined, capturando erros potenciais em tempo de execução durante a compilação.

Nomes de componentes normalizados e Vue Router v5

O Nuxt 4.3 realizou a atualização para o Vue Router v5, removendo a dependência do unplugin-vue-router. Para a maioria das aplicações, essa atualização é transparente.

As convenções de nomenclatura de componentes estão agora padronizadas. Um componente localizado em components/dashboard/MetricsCard.vue recebe o nome DashboardMetricsCard de forma consistente em todos os contextos — incluindo <KeepAlive>, Vue DevTools e utilitários de teste.

vue
<!-- app/pages/dashboard.vue -->
<template>
  <NuxtPage :keepalive="{
    include: ['DashboardMetricsCard', 'DashboardRecentActivity'],
  }" />
</template>

Projetos que utilizam <KeepAlive> com filtros de nomes de componentes precisam atualizar os nomes para corresponder a essa nova convenção. O comportamento anterior, onde o nome podia variar dependendo do contexto, não se aplica mais.

Lidando com mudanças importantes no gerenciamento do head

O Nuxt 4 vem com o Unhead v2, que remove diversas propriedades obsoletas de useHead e useSeoMeta:

app/pages/product/[id].vuetypescript
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)

// Unhead v2: remoção de vmid, hid, children, body
useSeoMeta({
  title: () => product.value?.name ?? 'Product',
  ogTitle: () => product.value?.name ?? 'Product',
  description: () => product.value?.description ?? '',
  ogImage: () => product.value?.imageUrl ?? '',
})
</script>

Para projetos que dependem de parâmetros de template ou ordenação por alias, essas funcionalidades devem ser instaladas como plugins explícitos:

app/plugins/unhead.tstypescript
import { TemplateParamsPlugin, AliasSortingPlugin } from '@unhead/vue/plugins'

export default defineNuxtPlugin({
  setup() {
    const unhead = injectHead()
    unhead.use(TemplateParamsPlugin)
    unhead.use(AliasSortingPlugin)
  },
})
Cronograma de suporte do Nuxt 3

O Nuxt 3 continua recebendo atualizações de segurança e correções de bugs críticos até 31 de julho de 2026. Após essa data, o Nuxt 3 não terá mais suporte. Planejar a migração agora evita manter aplicações em produção em um framework sem manutenção.

Checklist de migração e armadilhas comuns

O codemod automatizado lida com a maioria das mudanças, mas vários itens exigem atenção manual:

  • Remoção do window.__NUXT__: substituir por useNuxtApp().payload. Esse objeto global é removido após a hidratação no Nuxt 4.
  • Hook pages:extend: trocar para o novo hook pages:resolved, que é executado após a varredura dos metadados das páginas.
  • Booleano dedupe: substituir refresh({ dedupe: true }) por refresh({ dedupe: 'cancel' }) e false por 'defer'.
  • Estilos inline: apenas os estilos de componentes Vue são inseridos inline por padrão; o CSS global é carregado como arquivos separados. Adicionar features: { inlineStyles: true } para restaurar o comportamento do Nuxt 3.
  • clearNuxtState: agora redefine para os valores iniciais em vez de undefined. Usar clearNuxtState('key', { reset: false }) para manter o comportamento anterior.

Uma sequência de migração prática para aplicações em produção:

  1. Executar npx nuxt upgrade --dedupe e verificar se a aplicação compila corretamente
  2. Rodar o codemod: npx codemod@latest nuxt/4/migration-recipe
  3. Mover arquivos para app/ (automatizado pelo codemod file-structure)
  4. Atualizar as verificações de null para undefined na lógica de busca de dados
  5. Testar os componentes <KeepAlive> com os nomes normalizados
  6. Atualizar a verificação de tipos no CI para usar vue-tsc -b --noEmit
  7. Rodar a suíte completa de testes e corrigir os erros TypeScript expostos pelo noUncheckedIndexedAccess

Para aprofundar os conceitos de Vue e Nuxt, é possível explorar as questões de entrevista Vue/Nuxt no SharpSkill, ou consultar o guia de SSR e geração estática para obter contexto sobre estratégias de renderização que também se aplicam ao Nuxt 4.

Conclusão

  • O Nuxt 4.4 (versão atual em abril de 2026) estabiliza a estrutura do diretório app/, a busca de dados singleton e os contextos TypeScript divididos como padrões prontos para produção
  • O comando npx codemod@latest nuxt/4/migration-recipe automatiza a reestruturação de diretórios, a substituição de APIs obsoletas e as atualizações de busca de dados
  • A reatividade superficial via shallowRef melhora o desempenho de páginas de leitura intensiva sem exigir alterações de código na maioria dos casos
  • As configurações TypeScript separadas por contexto (app, server, shared, node) eliminam vazamentos de tipos entre contextos e melhoram o autocompletar do IDE
  • O Nuxt 3 atinge o fim de vida em 31 de julho de 2026 — migrar antes dessa data garante que as aplicações operem em uma versão com suporte e manutenção ativa
  • O Vue Router v5 e o Unhead v2 trazem APIs mais limpas ao custo de remover propriedades obsoletas que devem ser auditadas durante a migração

Comece a praticar!

Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.

Tags

#nuxt
#vue
#migração
#typescript
#tutorial

Compartilhar

Artigos relacionados