Vue.jsベースのフルスタックフレームワークとして広く採用されているNuxtが、2025年7月15日にバージョン4.0をリリースしました。約1年のテスト期間を経た安定性重視のメジャーアップデートであり、開発体験(DX)の向上に重点が置かれています。

Nuxt 4の中心的な設計方針は「Nuxt 3からの移行をスムーズにしつつ、プロジェクト構造・型安全性・パフォーマンスを底上げする」ことです。多くの破壊的変更はNuxt 3.xの段階で互換フラグとしてテストできる状態が1年以上続いていたため、段階的に対応できます。

ここでは、v4.0からv4.3までに導入された主要な機能変更を体系的に整理し、Nuxt 3プロジェクトからの移行判断に必要な情報をまとめています。

app/ディレクトリを軸にしたプロジェクト構成の再設計

Nuxt 4で最も目立つ変更が、プロジェクトのソースコードをapp/ディレクトリに集約する構成への移行です。

Nuxt 3ではcomponents/pages/composables/layouts/などをプロジェクトルート直下に配置していました。Nuxt 4ではこれらをapp/ディレクトリの配下に移動させ、設定ファイルやserver/ディレクトリとアプリケーションコードを明確に分離します。

# Nuxt 3の構成
my-project/
├── components/
├── composables/
├── layouts/
├── pages/
├── server/
├── nuxt.config.ts
└── app.vue

# Nuxt 4の構成
my-project/
├── app/
│   ├── components/
│   ├── composables/
│   ├── layouts/
│   ├── pages/
│   └── app.vue
├── server/
├── shared/
│   └── utils/
└── nuxt.config.ts

この変更によって得られる利点は主に3つあります。

  • 関心の分離が明確になる: クライアント寄りのコードと、サーバー側のコード、プロジェクト設定が物理的に分かれるため、大規模プロジェクトでのナビゲーションが容易になります
  • モノレポ構成との親和性: ルート直下にワークスペースの設定ファイルを置いても、アプリケーションコードと混在しません
  • shared/ディレクトリによるコード共有: 後述するshared/ディレクトリと合わせて、サーバーとクライアントで共通利用するロジックの管理が整理されます

なお、Nuxt 4でもルート直下にソースファイルを置く従来のレイアウトは引き続き動作します。app/ディレクトリが存在しない場合、Nuxt 4は自動的にルート直下をソースディレクトリとして認識します。

shared/ディレクトリ — サーバーとクライアントの共通コード置き場

Nuxt 4で新設されたshared/ディレクトリは、app/(クライアント側)とserver/の両方からインポートできる共有コードの格納場所です。

shared/
├── types/
   └── user.ts
├── utils/
   └── format-date.ts
└── constants.ts

shared/utils/shared/types/に配置したファイルはNuxtによって自動インポートの対象になります。バリデーションルール、定数定義、型定義など、サーバーとクライアントで重複しがちなコードを一箇所にまとめられるため、コードの一貫性が保ちやすくなります。

// shared/utils/validate-email.ts
export function validateEmail(email: string): boolean {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
}

// app/pages/register.vue — クライアント側で利用
const isValid = validateEmail(form.email)

// server/api/users.post.ts — サーバー側でも同じ関数を利用
const isValid = validateEmail(body.email)

データフェッチの挙動変更 — useFetchとuseAsyncData

Nuxt 4ではデータ取得コンポーザブルの内部挙動が見直されています。既存のAPIシグネチャ自体に大きな変更はありませんが、デフォルト値やリアクティビティの扱いが変わっているため、移行時に確認が必要です。

初期値がundefinedに統一

Nuxt 3ではuseFetchuseAsyncDatadataの初期値がnullでしたが、Nuxt 4ではundefinedに変更されました。テンプレート内でv-if="data"のような判定をしている箇所は影響を受けませんが、data === nullで明示的に未取得状態を判定しているコードは修正が必要です。

// Nuxt 3
const { data } = await useFetch('/api/users')
// data.value は取得前に null

// Nuxt 4
const { data } = await useFetch('/api/users')
// data.value は取得前に undefined

dataがshallowRefに変更

useFetch/useAsyncDataの戻り値datarefからshallowRefに変更されました。ネストの深いオブジェクトの内部プロパティを直接書き換えてもリアクティブに反応しなくなります。

// Nuxt 4ではこの書き方でUIが更新されない
data.value.users[0].name = '新しい名前'

// 代わりにdata.value全体を差し替える
data.value = {
  ...data.value,
  users: data.value.users.map((u, i) =>
    i === 0 ? { ...u, name: '新しい名前' } : u
  )
}

パフォーマンスの観点では、大量のデータを扱う画面でのリアクティビティコストが下がるメリットがあります。

dedupeオプションの仕様変更

useFetch/useAsyncDataのdedupeオプションが、boolean値(true/false)から文字列値('cancel'/'defer')に変更されました。dedupe: truededupe: 'cancel'に、dedupe: falsededupe: 'defer'に対応します。デフォルト値は'cancel'で、同じキーに対する新しいリクエストが発行されると進行中の古いリクエストが自動的にキャンセルされます。

pendingプロパティの計算方法の変更

pendingプロパティがcomputedプロパティに変更され、statuspendingの場合にのみtrueを返すようになりました。immediate: falseを指定した場合、初回リクエストが発行されるまでpendingfalseです。

AbortControllerによるキャンセル制御(v4.2〜)

v4.2でuseAsyncDataのハンドラにAbortControllerのsignalが渡されるようになりました。$fetchなどキャンセル可能なリクエストに対して、きめ細かいキャンセル制御が可能です。

const { data } = await useAsyncData('users', ({ signal }) => {
  return $fetch('/api/users', { signal })
})

refreshexecuteにもAbortControllerのsignalを直接渡せるため、ユーザー操作やコンポーネントのライフサイクルに応じたリクエスト中断が実装しやすくなっています。

TypeScript体験の底上げ

Nuxt 4ではTypeScriptの型推論が複数の面で改善されています。

より厳密な型チェック

nuxt.config.tstypescript.strictがデフォルトでtrueになりました。noUncheckedIndexedAccessなど、より厳格な型チェックオプションがデフォルトで有効化されます。

ルートパラメータの型推論

pages/ディレクトリのファイル名からルートパラメータの型が自動生成されるようになりました。useRouteで取得するパラメータに型が付くため、存在しないパラメータへのアクセスがコンパイル時に検出できます。

// pages/users/[id].vue の場合
const route = useRoute()
route.params.id // string 型として推論される
route.params.name // コンパイルエラー(存在しないパラメータ)

実験的TypeScriptプラグイン(v4.2〜)

v4.2でVSCode/エディタ向けのTypeScriptプラグインが実験的に導入されました。nuxt.config.tsのモジュール設定やランタイム設定に対する型補完・バリデーションが強化されます。

開発サーバーとCLIの高速化

Nuxt 4では開発時の体感速度を向上させるために、3つの最適化が実施されています。

最適化項目仕組み効果
V8コンパイルキャッシュの再利用Node.jsのバイトコードキャッシュを次回起動時に再利用コールドスタートの短縮
fs.watch APIへの切り替えポーリングではなくOSネイティブのファイル監視を利用CPU・メモリ使用量の低減
ソケットベースの内部通信CLI→Vite devサーバー間をネットワークポートからソケットに変更特にWindows環境でのオーバーヘッド削減

これらの変更は設定不要で自動的に適用されます。

Import Mapsによるビルドの安定性向上(v4.1〜)

v4.1で導入されたimport maps機能は、ビルド出力のチャンクハッシュ安定性を改善します。

エントリーチャンクの変更が、直接依存していない他のチャンクのハッシュに伝播しなくなります。これにより、CDNキャッシュやブラウザキャッシュの効率が向上し、小さなコード変更時にすべてのチャンクが再ダウンロードされる問題を軽減します。

この機能はHTML内に<script type="importmap">を挿入することで実現されており、import mapsをサポートしていないブラウザがビルドターゲットに含まれる場合は自動的に無効化されます。

Unhead v2とCapo.jsによるhead最適化

Nuxt 4ではheadタグ管理ライブラリ「Unhead」がv2にアップグレードされています。主な変更点は以下のとおりです。

  • Capo.jsによるタグ順序の最適化がデフォルトで有効: <head>内の要素を、ページの体感速度が最も向上する順序に自動で並べ替えます
  • 非推奨プロパティの削除: vmidhidchildrenbodyなどの旧来のプロパティが削除されました
  • Promiseを入力として渡す方法が非サポートに: 直接的な値またはリアクティブな値を渡す必要があります

旧来のプロパティを使用しているプロジェクトでは、unheadモジュールのレガシー互換モードを有効にすることで段階的に移行できます。

Rolldown(実験的サポート)

Rollup互換のRust製バンドラ「Rolldown」が、v4.1からViteの差し替え(rolldown-vite)として実験的に利用できます。ビルド速度の大幅な向上が見込まれますが、プロダクション利用にはまだ制約があります。

// nuxt.config.ts(Rolldown有効化の一例)
export default defineNuxtConfig({
  vite: {
    // rolldown-viteをoverrideとして導入した場合、
    // Nuxtが自動検出してビルド設定を調整
  }
})

Rolldownが利用可能になると、Nuxtは自動的に検出し、適切なビルド設定に切り替えます。

コンポーネント名の正規化

Nuxt 4ではcomponents/ディレクトリ内のコンポーネント名が、ディレクトリ名とファイル名をPascalCaseで結合した形に正規化されます。

app/components/
├── ui/
│   └── Button.vue    → <UiButton />
└── form/
    └── Input.vue     → <FormInput />

Nuxt 3ではコンポーネント名の生成ルールにゆらぎがあり得ましたが、Nuxt 4では一貫したルールで名前が決定されるため、大規模プロジェクトでの名前衝突リスクが低減します。

Nuxt 3から4への移行手順

Nuxt 4はNuxt 3からの段階的な移行を想定して設計されています。多くの破壊的変更はNuxt 3.x時点で互換フラグ経由でテスト可能でした。

手順1: パッケージのアップグレード

npx nuxt upgrade

手順2: 自動マイグレーションツールの実行

npx codemod nuxt/4/migration-recipe

codemods(自動コード変換ツール)が提供されており、ディレクトリ構造の移動やAPIの書き換えを半自動で実行できます。

手順3: 動作確認と調整

アップグレード後に確認すべき主なポイントは以下のとおりです。

確認項目チェック内容
データフェッチの初期値data === null判定をdata == nullまたは!dataに変更
shallowRefの影響ネストオブジェクトの直接変更箇所を、値の差し替えに修正
Unhead v2の非推奨APIhidvmidchildrenbodyの使用箇所を修正
モジュール互換性使用中のサードパーティモジュールがNuxt 4対応か確認
TypeScript厳格モードnoUncheckedIndexedAccessで新たに発生する型エラーへの対処

事前検証: Nuxt 3の互換フラグを利用する方法

Nuxt 3.x系でも以下の設定で、Nuxt 4の挙動を事前にテストできます。

// nuxt.config.ts(Nuxt 3.x)
export default defineNuxtConfig({
  future: {
    compatibilityVersion: 4
  }
})

この設定により、Nuxt 4のデフォルト挙動(ディレクトリ構成、データフェッチのデフォルト値など)がNuxt 3環境で有効化されます。段階的に問題を洗い出せるため、大規模プロジェクトでの安全な移行に有効です。

v4.0からv4.3までのリリース概要

バージョンリリース時期主な追加機能
v4.02025年7月app/ディレクトリ構成、shared/ディレクトリ、データフェッチ改善、TypeScript強化、Unhead v2、CLI高速化
v4.12025年9月Import Mapsによるビルド安定性向上、Rolldown実験的サポート、モジュール作者向けonInstall/onUpgradeフック
v4.22025年10月頃AbortControllerによるデータフェッチキャンセル、開発時エラーオーバーレイ、実験的TypeScriptプラグイン
v4.32026年1月頃レイアウト機能拡張、キャッシュ戦略強化、エラーオーバーレイのドラッグ・最小化対応、パフォーマンス改善

Nuxt 5への先行テスト(compatibilityVersion: 5)

Nuxt 4.2以降ではfuture.compatibilityVersion5に設定することで、開発中のNuxt 5の破壊的変更を先行テストできます。

export default defineNuxtConfig({
  future: {
    compatibilityVersion: 5
  }
})

現時点で有効化される主な変更として、Vite 6のEnvironment APIへの移行があります。開発サーバーが複数の環境(クライアント・サーバー)を並行管理する仕組みが刷新され、開発時と本番時の挙動差が縮小されます。

Nuxt 4とNext.jsの位置づけの違い

フロントエンドフレームワーク選定時に比較されることが多いNext.jsとの違いを整理します。

比較軸Nuxt 4Next.js(App Router)
ベースライブラリVue 3React
レンダリング戦略SSR / SSG / CSR / ハイブリッドをルートごとに選択可能SSR / SSG / CSR / ISR をルートごとに選択可能
サーバーエンジンNitro(h3ベース、エッジ対応)Node.js / Edge Runtime
データフェッチuseFetch / useAsyncData(コンポーザブル方式)Server Components / fetch(コンポーネント内直接)
型安全ルーティングファイル名ベースで自動生成手動定義が基本
バンドラVite(Rolldown実験対応)Turbopack(実験対応)/ Webpack

Vue.jsエコシステムを採用しているプロジェクトにとって、Nuxt 4はVue 3との統合が最も深いフレームワークです。Nitroによるエッジデプロイ対応やViteとの統合による高速な開発サーバーは、同エコシステム内でのアドバンテージになります。

まとめ

Nuxt 4はNuxt 3からの進化として、以下の領域を重点的に改善したリリースです。

  • プロジェクト構造: app/ディレクトリへの集約とshared/ディレクトリの新設により、コードの整理と共有が容易に
  • データフェッチ: shallowRef化によるパフォーマンス向上、AbortControllerによるキャンセル制御の追加
  • TypeScript: 厳格モードのデフォルト化、ルートパラメータの自動型推論
  • パフォーマンス: CLI・開発サーバーの高速化、Import Mapsによるビルドキャッシュ効率の向上
  • head管理: Unhead v2 + Capo.jsによる体感速度の最適化

Nuxt 3からの移行は、互換フラグによる事前検証とcodemodツールの活用で段階的に進められます。新規プロジェクトであればNuxt 4から開始し、既存プロジェクトではfuture.compatibilityVersion: 4で事前にテストしてから移行するアプローチが推奨されます。

公式の移行ガイドは Nuxt Upgrade Guide で確認できます。