Nuxt 4の新機能を徹底解説:ディレクトリ構造の刷新とNuxt 3からの移行ガイド(2026年版)
Nuxt 4で導入されたapp/ディレクトリ構造、シングルトンデータフェッチ層、shallow reactivity、TypeScript分割コンテキストについて、コード例を交えて詳しく解説します。

Nuxt 4は、アプリケーションコードと設定ファイルを明確に分離する新しいディレクトリ構造を導入しました。2025年7月にリリースされ、2026年4月時点でバージョン4.4に到達したこのメジャーアップデートは、シングルトンデータフェッチ層、shallowReactivityのデフォルト化、TypeScriptコンテキストの分割など、開発体験を大幅に改善する機能を備えています。Nuxt 2からNuxt 3への移行と比較すると、今回のアップグレードパスは格段にスムーズです。
NuxtチームはCodemodと連携し、ほとんどの移行ステップを自動化しています。npx codemod@latest nuxt/4/migration-recipe を実行すると、ディレクトリ再構築、データフェッチの更新、非推奨APIの置換が自動的に処理されます。
Nuxt 4のapp/ディレクトリ構造
Nuxt 4では、すべてのアプリケーションソースコードがデフォルトでapp/ディレクトリに配置されます。この変更は実際の開発上の課題を解決するものです。LinuxやWindowsのファイルウォッチャーは、アプリケーションコードがnode_modules/や.git/、設定ファイルと混在せず、専用のサブディレクトリに格納されている場合、大幅にパフォーマンスが向上します。
新しいディレクトリレイアウトは以下の通りです。
my-nuxt-app/
├─ app/
│ ├─ assets/
│ ├─ components/
│ ├─ composables/
│ ├─ layouts/
│ ├─ middleware/
│ ├─ pages/
│ ├─ plugins/
│ ├─ utils/
│ ├─ app.vue
│ ├─ app.config.ts
│ └─ error.vue
├─ content/
├─ public/
├─ shared/ # 新規:appとserver間で共有するコード
├─ server/
└─ nuxt.config.tsshared/ディレクトリは特筆すべき追加要素です。shared/に配置されたcomposableやユーティリティは、VueアプリとNitroサーバーの両方で自動インポートされます。バリデーションスキーマ、型定義、ユーティリティ関数をコンテキスト間で共有する際に、手動のimport文を記述する必要がなくなります。
Nuxt 3からNuxt 4へのステップバイステップ移行
アップグレードプロセスは1つのコマンドから始まります。Nuxtは既存のフラット構造を検出し、変更なしで動作を継続するため、段階的な移行が可能です。
# Nuxtのアップグレードと依存関係の重複解消
npx nuxt upgrade --dedupeパッケージのアップグレード後、アプリケーションファイルをapp/ディレクトリに移動します。
# ディレクトリ再構築の自動化
npx codemod@latest nuxt/4/file-structureこのcodemodにより、assets/、components/、composables/、layouts/、middleware/、pages/、plugins/、utils/、app.vue、error.vue、app.config.tsがapp/に移動されます。ルートに残すべきファイル(nuxt.config.ts、server/、public/、content/)はそのまま維持されます。
ディレクトリ再構築をすぐに行わない場合は、ソースディレクトリを明示的に設定できます。
export default defineNuxtConfig({
srcDir: '.',
dir: { app: 'app' },
})この設定により、Nuxt 4はプロジェクトルートからファイルを解決し、Nuxt 3と同じ動作を維持します。
シングルトンデータフェッチ層とリアクティブキー
Nuxt 4では、useAsyncDataとuseFetchのデータ管理方法が根本的に変更されました。同じキーを使用する複数のコンポーネントは、独立したコピーを保持する代わりに、単一のリアクティブ参照を共有するようになります。
export function useProductData(productId: string) {
return useAsyncData(
`product-${productId}`,
() => $fetch(`/api/products/${productId}`),
{
getCachedData: (key, nuxtApp, ctx) => {
// ctx.causeでフェッチの理由を判別可能
if (ctx.cause === 'refresh:manual') return undefined
return nuxtApp.payload.data[key]
},
},
)
}この新しいデータ層には3つの重要な変更点があります。
- 共有ref: 2つのコンポーネントで
useProductData('abc')を呼び出すと、同じdata、error、statusのrefが返されます。一方を更新すると、もう一方にも即座に反映されます。 - 自動クリーンアップ: あるキーを使用する最後のコンポーネントがアンマウントされると、関連データがメモリから解放されます。
- リアクティブキー: キーをcomputedまたはrefでラップすると、値の変更時に自動的にデータが再フェッチされます。
getCachedDataコールバックは、causeプロパティ('initial'、'refresh:hook'、'refresh:manual'、'watch')を持つコンテキストオブジェクトを受け取るようになり、キャッシュデータの提供と新規フェッチの使い分けをきめ細かく制御できます。
useAsyncData/useFetchのdataとerrorのデフォルト値がnullからundefinedに変更されました。=== nullチェックを=== undefinedに更新するか、緩い等価演算子を使用する必要があります。
Shallow Reactivityによるパフォーマンス最適化
Nuxt 4では、useAsyncDataとuseFetchのdataがrefではなくshallowRefをデフォルトで使用するようになりました。Vueはネストされたプロパティを再帰的に追跡しなくなるため、深くネストされたオブジェクトや大規模な配列を含むAPIレスポンスに対して、計測可能なパフォーマンス改善が得られます。
<script setup lang="ts">
// dataはデフォルトでshallowRefになる
const { data: metrics } = await useFetch('/api/dashboard/metrics')
// 直接的なプロパティ変更はリアクティビティをトリガーしない
// metrics.value.visits = 100 // 再レンダリングが発生しない
// 値全体を置換すると更新がトリガーされる
metrics.value = { ...metrics.value, visits: 100 }
// 特定の呼び出しでディープリアクティビティを有効化
const { data: settings } = await useFetch('/api/settings', {
deep: true,
})
</script>ダッシュボード、商品一覧、記事ページなど、ほとんどの読み取り専用データ表示では、shallow reactivityはコード変更なしで動作します。フォームやネストされたプロパティを直接変更するインタラクティブUIには、deep: trueオプションが引き続き利用できます。
Vue.js / Nuxt.jsの面接対策はできていますか?
インタラクティブなシミュレーター、flashcards、技術テストで練習しましょう。
TypeScriptコンテキスト分割と型安全性の強化
Nuxt 4では、プロジェクト内の各コンテキストに対して個別のTypeScript設定が生成されます。
.nuxt/tsconfig.app.json— Vueアプリケーションコード用.nuxt/tsconfig.server.json— Nitroサーバーコード用.nuxt/tsconfig.shared.json— 共有ユーティリティ用.nuxt/tsconfig.node.json— ビルド時設定用
この分離により、IDEがクライアントコード内でサーバー専用APIを提案したり、その逆が起きたりすることがなくなります。プロジェクトルートのtsconfig.jsonは、4つすべての設定を参照する構成になります。
{
"files": [],
"references": [
{ "path": "./.nuxt/tsconfig.app.json" },
{ "path": "./.nuxt/tsconfig.server.json" },
{ "path": "./.nuxt/tsconfig.shared.json" },
{ "path": "./.nuxt/tsconfig.node.json" }
]
}CIでの型チェックも変更があります。vue-tscコマンドは、プロジェクト参照を正しく処理するために-bフラグ(ビルドモード)が必要になります。
# 変更前(Nuxt 3)
nuxt prepare && vue-tsc --noEmit
# 変更後(Nuxt 4)
nuxt prepare && vue-tsc -b --noEmitもう1つのTypeScriptの変更点として、compilerOptions.noUncheckedIndexedAccessがデフォルトでtrueに設定されるようになりました。配列要素やオブジェクトプロパティへのインデックスアクセスはT | undefinedを返すようになり、コンパイル時に潜在的なランタイムエラーを検出できます。
コンポーネント名の正規化とVue Router v5
Nuxt 4.3ではVue Router v5にアップグレードされ、unplugin-vue-routerへの依存が解消されました。ほとんどのアプリケーションでは、このアップグレードは透過的に行われます。
コンポーネントの命名規則が標準化されました。components/dashboard/MetricsCard.vueにあるコンポーネントは、<KeepAlive>、Vue DevTools、テストユーティリティを含むすべてのコンテキストで一貫してDashboardMetricsCardという名前が付けられます。
<!-- app/pages/dashboard.vue -->
<template>
<NuxtPage :keepalive="{
include: ['DashboardMetricsCard', 'DashboardRecentActivity'],
}" />
</template>コンポーネント名フィルターを使用した<KeepAlive>を利用しているプロジェクトでは、この新しい命名規則に合わせた更新が必要です。コンテキストによって名前が異なる以前の動作は適用されなくなりました。
Head管理における破壊的変更への対応
Nuxt 4にはUnhead v2が同梱されており、useHeadとuseSeoMetaからいくつかの非推奨プロパティが削除されています。
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
// Unhead v2:vmid、hid、children、bodyプロパティが削除
useSeoMeta({
title: () => product.value?.name ?? 'Product',
ogTitle: () => product.value?.name ?? 'Product',
description: () => product.value?.description ?? '',
ogImage: () => product.value?.imageUrl ?? '',
})
</script>テンプレートパラメータやエイリアスソートに依存しているプロジェクトでは、これらを明示的なプラグインとしてインストールする必要があります。
import { TemplateParamsPlugin, AliasSortingPlugin } from '@unhead/vue/plugins'
export default defineNuxtPlugin({
setup() {
const unhead = injectHead()
unhead.use(TemplateParamsPlugin)
unhead.use(AliasSortingPlugin)
},
})Nuxt 3は2026年7月31日までセキュリティアップデートと重要なバグ修正を受け続けます。その日以降、Nuxt 3はサポート対象外となります。EOLフレームワーク上で本番アプリケーションを運用することを避けるため、今のうちに移行計画を立てることが推奨されます。
移行チェックリストと注意すべきポイント
自動codemodがほとんどの変更を処理しますが、手動対応が必要な項目もあります。
window.__NUXT__の削除:useNuxtApp().payloadに置き換えが必要です。このグローバルオブジェクトはNuxt 4ではハイドレーション後に削除されます。pages:extendフック: ページメタスキャン後に実行される新しいpages:resolvedフックに切り替えが必要です。dedupeブーリアン:refresh({ dedupe: true })をrefresh({ dedupe: 'cancel' })に、falseを'defer'に置き換えます。- インラインスタイル: デフォルトではVueコンポーネントスタイルのみがインライン化され、グローバルCSSは別ファイルとして読み込まれます。Nuxt 3の動作に戻すには
features: { inlineStyles: true }を追加します。 clearNuxtState:undefinedではなく初期値にリセットされるようになりました。以前の動作が必要な場合はclearNuxtState('key', { reset: false })を使用します。
本番アプリケーション向けの実践的な移行手順は以下の通りです。
npx nuxt upgrade --dedupeを実行し、アプリケーションのビルドを確認- codemodを実行:
npx codemod@latest nuxt/4/migration-recipe - ファイルを
app/に移動(file-structure codemodにより自動化) - データフェッチロジックの
nullチェックをundefinedに更新 - 正規化された名前で
<KeepAlive>コンポーネントをテスト - CIの型チェックを
vue-tsc -b --noEmitに更新 - テストスイート全体を実行し、
noUncheckedIndexedAccessによって検出されたTypeScriptエラーを修正
VueとNuxtの概念をより深く理解するには、SharpSkillのVue/Nuxt面接対策問題を参照するか、Nuxt 4にも引き継がれるレンダリング戦略の背景としてSSRと静的生成ガイドを確認してください。
まとめ
- Nuxt 4.4(2026年4月時点の最新版)は、
app/ディレクトリ構造、シングルトンデータフェッチ、分割TypeScriptコンテキストを本番環境対応のデフォルトとして確立しています npx codemod@latest nuxt/4/migration-recipeコマンドにより、ディレクトリ再構築、非推奨APIの置換、データフェッチの更新が自動化されますshallowRefによるshallow reactivityは、ほとんどのケースでコード変更不要のままパフォーマンスを改善します- コンテキストごとの個別TypeScript設定(app、server、shared、node)により、コンテキスト間の型リークが解消され、IDEの補完精度が向上します
- Nuxt 3は2026年7月31日にサポート終了を迎えるため、それ以前の移行がサポート対象バージョンの維持に必要です
- Vue Router v5とUnhead v2はより整理されたAPIを提供しますが、非推奨プロパティの削除に伴い移行時の確認が求められます
今すぐ練習を始めましょう!
面接シミュレーターと技術テストで知識をテストしましょう。
タグ
共有
関連記事

Vue 3 Pinia vs Vuex徹底比較:2026年の状態管理と面接対策ガイド
Vue 3におけるPiniaとVuexの違いを徹底的に比較します。Options StoreとSetup Store、TypeScript統合、ストア間通信、Vuexからの移行手順、SSR対応まで、2026年の面接で問われる状態管理の知識を実践的なコード例とともに解説します。

Nuxt 3: SSR と静的生成 完全ガイド
Nuxt 3 で SSR と静的生成を使いこなしましょう。useFetch から route rules まで、Vue.js アプリケーションのパフォーマンスを最適化する方法を解説します。

Vue.js面接の必須質問: 内定をつかむための25問
Vue.js面接の準備に役立つ必須質問25問。リアクティビティからcomposablesまで、次の面接を勝ち抜くための要点を押さえます。