# Nuxt 4 in 2026: New Directory Structure and Migration from Nuxt 3 > Complete guide to Nuxt 4 directory structure, migration from Nuxt 3, data fetching changes, and TypeScript improvements. Step-by-step tutorial with code examples. - Published: 2026-05-01 - Updated: 2026-05-01 - Author: SharpSkill - Tags: nuxt, vue, migration, typescript, tutorial - Reading time: 10 min --- Nuxt 4 introduces a redesigned directory structure that separates application code from configuration, along with a singleton data fetching layer, shallow reactivity defaults, and split TypeScript contexts. Released in July 2025 and now at version 4.4, this major release focuses on evolution rather than revolution — making the migration path from Nuxt 3 significantly smoother than the Nuxt 2 to 3 jump. > **Automated Migration Available** > > The Nuxt team partnered with Codemod to automate most migration steps. Run `npx codemod@latest nuxt/4/migration-recipe` to handle directory restructuring, data fetching updates, and deprecated API replacements automatically. ## The New app/ Directory Structure in Nuxt 4 Nuxt 4 moves all application source code into an `app/` directory by default. This separation solves a real problem: file watchers on Linux and Windows perform significantly better when application code lives in a dedicated subdirectory rather than mixed with `node_modules/`, `.git/`, and configuration files. The new layout follows this structure: ```text my-nuxt-app/ ├─ app/ │ ├─ assets/ │ ├─ components/ │ ├─ composables/ │ ├─ layouts/ │ ├─ middleware/ │ ├─ pages/ │ ├─ plugins/ │ ├─ utils/ │ ├─ app.vue │ ├─ app.config.ts │ └─ error.vue ├─ content/ ├─ public/ ├─ shared/ # New: code shared between app and server ├─ server/ └─ nuxt.config.ts ``` The `shared/` directory is a notable addition. Any composable or utility placed in `shared/` becomes auto-imported in both the Vue app and the Nitro server, eliminating the need for manual imports when sharing validation schemas, type definitions, or utility functions across contexts. ## Step-by-Step Migration from Nuxt 3 to Nuxt 4 The upgrade process starts with a single command. Nuxt detects the existing flat structure and continues working without any changes, so the migration can happen incrementally. ```bash # Upgrade Nuxt and deduplicate dependencies npx nuxt upgrade --dedupe ``` After upgrading the package, move application files into the `app/` directory: ```bash # Automate the directory restructuring npx codemod@latest nuxt/4/file-structure ``` This codemod moves `assets/`, `components/`, `composables/`, `layouts/`, `middleware/`, `pages/`, `plugins/`, `utils/`, `app.vue`, `error.vue`, and `app.config.ts` into `app/`. Files that belong at the root — `nuxt.config.ts`, `server/`, `public/`, and `content/` — stay in place. For projects that need to delay the restructuring, set the source directory explicitly: ```typescript // nuxt.config.ts export default defineNuxtConfig({ srcDir: '.', dir: { app: 'app' }, }) ``` This configuration tells Nuxt 4 to resolve files from the project root, matching the Nuxt 3 behavior exactly. ## Singleton Data Fetching Layer and Reactive Keys Nuxt 4 fundamentally changes how `useAsyncData` and `useFetch` manage data. Multiple components calling the same key now share a single reactive reference instead of maintaining independent copies. ```typescript // app/composables/useProductData.ts export function useProductData(productId: string) { return useAsyncData( `product-${productId}`, () => $fetch(`/api/products/${productId}`), { getCachedData: (key, nuxtApp, ctx) => { // ctx.cause tells why the fetch is happening if (ctx.cause === 'refresh:manual') return undefined return nuxtApp.payload.data[key] }, }, ) } ``` Three changes stand out in this new data layer: - **Shared refs**: calling `useProductData('abc')` in two components returns the same `data`, `error`, and `status` refs. Updating one updates both. - **Automatic cleanup**: when the last component using a key unmounts, Nuxt frees the associated data from memory. - **Reactive keys**: wrapping a key in a computed or ref triggers automatic refetching when the value changes. The `getCachedData` callback now receives a context object with a `cause` property (`'initial'`, `'refresh:hook'`, `'refresh:manual'`, or `'watch'`), enabling fine-grained control over when to serve cached data versus fetching fresh data. > **Default Values Changed** > > Data and error from `useAsyncData`/`useFetch` now default to `undefined` instead of `null`. Update any `=== null` checks to `=== undefined` or use a loose equality check. ## Shallow Reactivity by Default for Better Performance Nuxt 4 switches `data` from `useAsyncData` and `useFetch` to `shallowRef` instead of `ref`. Vue no longer recursively tracks every nested property, which delivers measurable performance improvements for API responses with deeply nested objects or large arrays. ```typescript // app/pages/dashboard.vue ``` For most read-only data displays (dashboards, product listings, article pages), shallow reactivity works without any code changes. The `deep: true` option remains available for forms or interactive UIs that mutate nested properties directly. ## TypeScript Context Splitting and Improved Type Safety Nuxt 4 generates separate TypeScript configurations for each context in the project: - `.nuxt/tsconfig.app.json` — Vue application code - `.nuxt/tsconfig.server.json` — Nitro server code - `.nuxt/tsconfig.shared.json` — Shared utilities - `.nuxt/tsconfig.node.json` — Build-time configuration This separation means the IDE no longer suggests server-only APIs in client code, and vice versa. A single `tsconfig.json` at the project root references all four configs: ```json { "files": [], "references": [ { "path": "./.nuxt/tsconfig.app.json" }, { "path": "./.nuxt/tsconfig.server.json" }, { "path": "./.nuxt/tsconfig.shared.json" }, { "path": "./.nuxt/tsconfig.node.json" } ] } ``` Type checking in CI also changes. The `vue-tsc` command now requires the `-b` flag (build mode) to process project references correctly: ```bash # Before (Nuxt 3) nuxt prepare && vue-tsc --noEmit # After (Nuxt 4) nuxt prepare && vue-tsc -b --noEmit ``` Another TypeScript change: `compilerOptions.noUncheckedIndexedAccess` is `true` by default. Accessing an array element or object property by index now returns `T | undefined`, catching potential runtime errors at compile time. ## Normalized Component Names and Vue Router v5 Nuxt 4.3 upgraded to Vue Router v5, removing the dependency on `unplugin-vue-router`. For most applications, this upgrade is transparent. Component naming conventions are now standardized. A component at `components/dashboard/MetricsCard.vue` gets the name `DashboardMetricsCard` consistently across all contexts — including ``, Vue DevTools, and test utilities. ```vue ``` Projects using `` with component name filters need to update the names to match this new convention. The previous behavior, where the name could vary depending on context, no longer applies. ## Handling Breaking Changes in Head Management Nuxt 4 ships with Unhead v2, which removes several deprecated properties from `useHead` and `useSeoMeta`: ```typescript // app/pages/product/[id].vue ``` For projects relying on template parameters or alias sorting, install these as explicit plugins: ```typescript // app/plugins/unhead.ts import { TemplateParamsPlugin, AliasSortingPlugin } from '@unhead/vue/plugins' export default defineNuxtPlugin({ setup() { const unhead = injectHead() unhead.use(TemplateParamsPlugin) unhead.use(AliasSortingPlugin) }, }) ``` > **Nuxt 3 Support Timeline** > > Nuxt 3 continues to receive security updates and critical bug fixes until July 31, 2026. After that date, Nuxt 3 becomes unsupported. Planning the migration now avoids running production applications on an EOL framework. ## Migration Checklist and Common Pitfalls The automated codemod handles most changes, but several items require manual attention: - **`window.__NUXT__` removal**: replace with `useNuxtApp().payload`. This global object is deleted after hydration in Nuxt 4. - **`pages:extend` hook**: switch to the new `pages:resolved` hook, which runs after page meta scanning. - **`dedupe` boolean**: replace `refresh({ dedupe: true })` with `refresh({ dedupe: 'cancel' })` and `false` with `'defer'`. - **Inline styles**: only Vue component styles are inlined by default; global CSS loads as separate files. Add `features: { inlineStyles: true }` to restore the Nuxt 3 behavior. - **`clearNuxtState`**: now resets to initial values instead of `undefined`. Use `clearNuxtState('key', { reset: false })` for the old behavior. A practical migration sequence for production applications: 1. Run `npx nuxt upgrade --dedupe` and verify the application builds 2. Run the codemod: `npx codemod@latest nuxt/4/migration-recipe` 3. Move files to `app/` (automated by the file-structure codemod) 4. Update `null` checks to `undefined` in data fetching logic 5. Test `` components with normalized names 6. Update CI type checking to use `vue-tsc -b --noEmit` 7. Run the full test suite and fix any TypeScript errors exposed by `noUncheckedIndexedAccess` For deeper coverage of Vue and Nuxt concepts, explore the [Vue/Nuxt interview questions](/technologies/vue-nuxt/interview-questions/nuxt-fundamentals) on SharpSkill, or review the [SSR and static generation guide](/blog/vue-nuxt/nuxt-3-ssr-static-generation) for background on rendering strategies that carry over to Nuxt 4. ## Conclusion - Nuxt 4.4 (current as of April 2026) stabilizes the `app/` directory structure, singleton data fetching, and split TypeScript contexts as production-ready defaults - The `npx codemod@latest nuxt/4/migration-recipe` command automates directory restructuring, deprecated API replacements, and data fetching updates - Shallow reactivity via `shallowRef` improves performance for read-heavy pages without requiring code changes in most cases - Separate TypeScript configs per context (app, server, shared, node) eliminate cross-context type leaks and improve IDE autocompletion - Nuxt 3 reaches end-of-life on July 31, 2026 — migrating before that date keeps applications on a supported, actively maintained version - Vue Router v5 and Unhead v2 bring cleaner APIs at the cost of removing deprecated properties that should be audited during migration --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/en/blog/vue-nuxt/nuxt-4-directory-structure-migration