Nuxt 4 en 2026 : nouvelle structure de répertoires et migration depuis Nuxt 3

Guide complet de migration vers Nuxt 4 : structure de répertoires app/, couche de récupération de données singleton, améliorations TypeScript et instructions de mise à jour pas à pas avec exemples de code.

Nuxt 4 nouvelle structure de répertoires et migration depuis Nuxt 3

Nuxt 4 introduit une structure de répertoires repensée qui sépare le code applicatif de la configuration, accompagnée d'une couche de récupération de données singleton, de valeurs par défaut en réactivité superficielle et de contextes TypeScript séparés. Publiée en juillet 2025 et désormais en version 4.4, cette mise à jour majeure privilégie l'évolution plutôt que la révolution, rendant le chemin de migration depuis Nuxt 3 considérablement plus fluide que le passage de Nuxt 2 à 3.

Migration automatisée disponible

L'équipe Nuxt s'est associée à Codemod pour automatiser la plupart des étapes de migration. Il suffit d'exécuter npx codemod@latest nuxt/4/migration-recipe pour gérer la restructuration des répertoires, les mises à jour de la récupération de données et le remplacement des API dépréciées automatiquement.

La nouvelle structure du répertoire app/ dans Nuxt 4

Nuxt 4 déplace tout le code source de l'application dans un répertoire app/ par défaut. Cette séparation résout un problème concret : les observateurs de fichiers sous Linux et Windows sont nettement plus performants lorsque le code applicatif se trouve dans un sous-répertoire dédié plutôt que mélangé avec node_modules/, .git/ et les fichiers de configuration.

La nouvelle organisation suit cette structure :

text
my-nuxt-app/
├─ app/
│  ├─ assets/
│  ├─ components/
│  ├─ composables/
│  ├─ layouts/
│  ├─ middleware/
│  ├─ pages/
│  ├─ plugins/
│  ├─ utils/
│  ├─ app.vue
│  ├─ app.config.ts
│  └─ error.vue
├─ content/
├─ public/
├─ shared/         # Nouveau : code partagé entre app et serveur
├─ server/
└─ nuxt.config.ts

Le répertoire shared/ constitue un ajout notable. Tout composable ou utilitaire placé dans shared/ devient auto-importé à la fois dans l'application Vue et le serveur Nitro, éliminant la nécessité d'importations manuelles pour partager des schémas de validation, des définitions de types ou des fonctions utilitaires entre les deux contextes.

Migration pas à pas de Nuxt 3 vers Nuxt 4

Le processus de mise à jour commence par une seule commande. Nuxt détecte la structure plate existante et continue de fonctionner sans aucune modification, permettant ainsi une migration incrémentale.

bash
# Mettre à jour Nuxt et dédupliquer les dépendances
npx nuxt upgrade --dedupe

Après la mise à jour du package, il faut déplacer les fichiers applicatifs dans le répertoire app/ :

bash
# Automatiser la restructuration des répertoires
npx codemod@latest nuxt/4/file-structure

Ce codemod déplace assets/, components/, composables/, layouts/, middleware/, pages/, plugins/, utils/, app.vue, error.vue et app.config.ts dans app/. Les fichiers qui doivent rester à la racine — nuxt.config.ts, server/, public/ et content/ — restent en place.

Pour les projets nécessitant un report de la restructuration, le répertoire source peut être défini explicitement :

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

Cette configuration indique à Nuxt 4 de résoudre les fichiers depuis la racine du projet, reproduisant exactement le comportement de Nuxt 3.

Couche de récupération de données singleton et clés réactives

Nuxt 4 modifie fondamentalement la façon dont useAsyncData et useFetch gèrent les données. Plusieurs composants appelant la même clé partagent désormais une seule référence réactive au lieu de maintenir des copies indépendantes.

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

Trois changements majeurs caractérisent cette nouvelle couche de données :

  • Références partagées : appeler useProductData('abc') dans deux composants renvoie les mêmes refs data, error et status. La mise à jour de l'un met à jour l'autre.
  • Nettoyage automatique : lorsque le dernier composant utilisant une clé est démonté, Nuxt libère les données associées de la mémoire.
  • Clés réactives : encapsuler une clé dans un computed ou une ref déclenche automatiquement un nouveau fetch lorsque la valeur change.

Le callback getCachedData reçoit désormais un objet context avec une propriété cause ('initial', 'refresh:hook', 'refresh:manual' ou 'watch'), permettant un contrôle granulaire sur le moment de servir des données en cache plutôt que de récupérer des données fraîches.

Valeurs par défaut modifiées

Les propriétés data et error de useAsyncData/useFetch ont désormais la valeur par défaut undefined au lieu de null. Il convient de mettre à jour les vérifications === null en === undefined ou d'utiliser une comparaison non stricte.

Réactivité superficielle par défaut pour de meilleures performances

Nuxt 4 bascule data de useAsyncData et useFetch vers shallowRef au lieu de ref. Vue ne suit plus récursivement chaque propriété imbriquée, ce qui apporte des améliorations de performance mesurables pour les réponses d'API contenant des objets profondément imbriqués ou de grands tableaux.

app/pages/dashboard.vuetypescript
<script setup lang="ts">
// Les données utilisent désormais shallowRef par défaut
const { data: metrics } = await useFetch('/api/dashboard/metrics')

// La mutation directe de propriétés ne déclenche pas la réactivité
// metrics.value.visits = 100  // Ne provoquera pas de re-rendu

// Remplacer la valeur entière pour déclencher les mises à jour
metrics.value = { ...metrics.value, visits: 100 }

// Ou activer la réactivité profonde pour cet appel spécifique
const { data: settings } = await useFetch('/api/settings', {
  deep: true,
})
</script>

Pour la plupart des affichages en lecture seule (tableaux de bord, listes de produits, pages d'articles), la réactivité superficielle fonctionne sans aucune modification de code. L'option deep: true reste disponible pour les formulaires ou les interfaces interactives qui modifient directement des propriétés imbriquées.

Prêt à réussir tes entretiens Vue.js / Nuxt.js ?

Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.

Séparation des contextes TypeScript et sécurité des types améliorée

Nuxt 4 génère des configurations TypeScript distinctes pour chaque contexte du projet :

  • .nuxt/tsconfig.app.json — Code de l'application Vue
  • .nuxt/tsconfig.server.json — Code du serveur Nitro
  • .nuxt/tsconfig.shared.json — Utilitaires partagés
  • .nuxt/tsconfig.node.json — Configuration au moment du build

Cette séparation signifie que l'IDE ne suggère plus les API réservées au serveur dans le code client, et inversement. Un seul tsconfig.json à la racine du projet référence les quatre configurations :

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

La vérification des types en CI change également. La commande vue-tsc nécessite désormais le drapeau -b (mode build) pour traiter correctement les références de projet :

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

# Après (Nuxt 4)
nuxt prepare && vue-tsc -b --noEmit

Autre modification TypeScript : compilerOptions.noUncheckedIndexedAccess est activé par défaut (true). L'accès à un élément de tableau ou une propriété d'objet par index renvoie désormais T | undefined, capturant les erreurs potentielles à l'exécution dès la compilation.

Noms de composants normalisés et Vue Router v5

Nuxt 4.3 a effectué la mise à niveau vers Vue Router v5, supprimant la dépendance à unplugin-vue-router. Pour la majorité des applications, cette mise à niveau est transparente.

Les conventions de nommage des composants sont désormais standardisées. Un composant situé dans components/dashboard/MetricsCard.vue obtient le nom DashboardMetricsCard de manière cohérente dans tous les contextes — y compris <KeepAlive>, Vue DevTools et les utilitaires de test.

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

Les projets utilisant <KeepAlive> avec des filtres de noms de composants doivent mettre à jour les noms pour correspondre à cette nouvelle convention. Le comportement précédent, où le nom pouvait varier selon le contexte, ne s'applique plus.

Gestion des changements majeurs dans la gestion du head

Nuxt 4 embarque Unhead v2, qui supprime plusieurs propriétés dépréciées de useHead et 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 : suppression 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>

Pour les projets s'appuyant sur les paramètres de template ou le tri par alias, ces fonctionnalités doivent être installées comme plugins explicites :

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

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

Nuxt 3 continue de recevoir des correctifs de sécurité et des corrections de bogues critiques jusqu'au 31 juillet 2026. Après cette date, Nuxt 3 ne sera plus supporté. Planifier la migration dès maintenant évite d'exploiter des applications en production sur un framework en fin de vie.

Checklist de migration et pièges courants

Le codemod automatisé gère la plupart des changements, mais plusieurs éléments nécessitent une attention manuelle :

  • Suppression de window.__NUXT__ : remplacer par useNuxtApp().payload. Cet objet global est supprimé après l'hydratation dans Nuxt 4.
  • Hook pages:extend : basculer vers le nouveau hook pages:resolved, qui s'exécute après le scan des méta-données des pages.
  • Booléen dedupe : remplacer refresh({ dedupe: true }) par refresh({ dedupe: 'cancel' }) et false par 'defer'.
  • Styles inline : seuls les styles des composants Vue sont inlinés par défaut ; le CSS global est chargé sous forme de fichiers séparés. Ajouter features: { inlineStyles: true } pour restaurer le comportement de Nuxt 3.
  • clearNuxtState : réinitialise désormais aux valeurs initiales au lieu de undefined. Utiliser clearNuxtState('key', { reset: false }) pour retrouver l'ancien comportement.

Une séquence de migration pratique pour les applications en production :

  1. Exécuter npx nuxt upgrade --dedupe et vérifier que l'application se build correctement
  2. Lancer le codemod : npx codemod@latest nuxt/4/migration-recipe
  3. Déplacer les fichiers dans app/ (automatisé par le codemod file-structure)
  4. Mettre à jour les vérifications null en undefined dans la logique de récupération de données
  5. Tester les composants <KeepAlive> avec les noms normalisés
  6. Mettre à jour la vérification des types en CI pour utiliser vue-tsc -b --noEmit
  7. Lancer la suite de tests complète et corriger les erreurs TypeScript révélées par noUncheckedIndexedAccess

Pour approfondir les concepts Vue et Nuxt, il est possible d'explorer les questions d'entretien Vue/Nuxt sur SharpSkill, ou de consulter le guide SSR et génération statique pour des informations sur les stratégies de rendu qui s'appliquent également à Nuxt 4.

Conclusion

  • Nuxt 4.4 (version actuelle en avril 2026) stabilise la structure du répertoire app/, la récupération de données singleton et les contextes TypeScript séparés comme valeurs par défaut prêtes pour la production
  • La commande npx codemod@latest nuxt/4/migration-recipe automatise la restructuration des répertoires, le remplacement des API dépréciées et les mises à jour de la récupération de données
  • La réactivité superficielle via shallowRef améliore les performances des pages en lecture intensive sans nécessiter de modifications de code dans la plupart des cas
  • Les configurations TypeScript séparées par contexte (app, server, shared, node) éliminent les fuites de types inter-contextes et améliorent l'autocomplétion de l'IDE
  • Nuxt 3 atteint sa fin de vie le 31 juillet 2026 — migrer avant cette date garantit le fonctionnement des applications sur une version supportée et activement maintenue
  • Vue Router v5 et Unhead v2 apportent des API plus propres au prix de la suppression de propriétés dépréciées qui doivent être auditées lors de la migration

Tags

#nuxt
#vue
#migration
#typescript
#tutoriel

Partager

Articles similaires