Nuxt 4 完全ガイド【2026年最新】|app/ ディレクトリ構造・Auto-imports・useFetch/useAsyncData 改善・Nitro サーバールート・TypeScript プロジェクト分割・Pinia 連携・Nuxt 3 からの移行まで実戦パターンで解説

Vue エコシステムのフルスタックメタフレームワーク Nuxt は、2025 年 7 月の 4.0 安定版で大きく生まれ変わりました。プロジェクトルートに散らばっていた設定・ソース・サーバーコードが app/server/ に明確に分離され、useFetch / useAsyncData の挙動も同キー共有・shallowRef 既定・undefined 既定へと最適化。TypeScript プロジェクトが「アプリ / サーバー / 共有 / ビルダー」の 4 つに自動分割され、型推論の精度が劇的に上がりました。

React + Next.js、Svelte + SvelteKit と並ぶ 3 大フルスタック選択肢のひとつとして、Nuxt 4 は「Vue 3 Composition API の書きやすさNitro による任意プロバイダへのデプロイAuto-imports による最小ボイラープレート」という独自ポジションを強化しました。日本語の Vue コミュニティも依然強く、2026 年はエンタープライズ領域で採用が伸びています。

この記事では Nuxt 4.x を前提に、新しい app/ ディレクトリ構造、Auto-imports、Pages と File-based Routing、Nitro サーバールート、改善された useFetch、Layouts / Middleware、Nuxt Modules、Pinia での状態管理、TypeScript プロジェクト分割、各プロバイダへのデプロイ、compatibilityVersion 4 による段階移行、Nuxt 3 → 4 の破壊的変更と自動移行 codemod、落とし穴まで一気通貫で解説します。

スポンサーリンク

2026 年 4 月時点の Nuxt バージョン整理

リリース 時期 主なハイライト
Nuxt 3.x 2022 年〜 Vue 3 + Vite + Nitro の全面書き換え、compatibilityVersion: 4 で v4 挙動を事前テスト可能
Nuxt 4.0 2025 年 7 月 app/ ディレクトリ化、useFetch / useAsyncData 同キー共有、datashallowRef に、null 既定 → undefined、TypeScript プロジェクト分割、SPA loading template 外側配置
Nuxt 4.1〜4.x 2025 年末〜2026 年 CLI 高速化、useFetch 型推論改善、Nitro Tasks 改善、Hybrid rendering strategies 拡張
推奨 2026 年 4 月 Nuxt 4.x 系。新規プロジェクトは最初からこの系列
Nuxt 4 のコンセプト: 「安定性フォーカスのメジャー」です。機能追加は控えめで、ディレクトリ構造・データフェッチ挙動・TypeScript プロジェクト構成を「今どきの Vue SSR アプリにふさわしい形」に整えるのが主眼。そのため移行の大半は npx codemod nuxt/4/migration-recipe で自動化でき、手作業が最小になるよう設計されています。

Nuxt とは ── Vue フルスタックメタフレームワーク

Nuxt は Vue 3 上に構築されたフルスタックメタフレームワークです。フロントエンドの Vue アプリに加え、API ルート(Nitro)、SSR / SSG / SPA / Edge レンダリング、ファイルベースルーティング、Auto-imports、モジュールエコシステムを 1 パッケージで提供します。

機能 内容
Vue 3 統合 Composition API / script setup / reactivity をそのまま使える。詳細は TypeScript × Vue 3 Composition API 完全ガイド
File-based Routing app/pages/**/*.vue が自動的にルートに。動的・ネスト・キャッチオール対応
Auto-imports components / composables / utils / Vue API / Nuxt API が import 不要で使える
Nitro サーバー server/api/**/*.ts が API ルートに。任意のプロバイダ(Node / Vercel / Cloudflare / Bun / Deno / Netlify / AWS Lambda)へ同じコードでデプロイ
Rendering Modes SSR / SSG / SPA / Hybrid(ルート単位で選択可能)
Modules 200+ の公式 / コミュニティモジュール(@nuxtjs/tailwindcss@pinia/nuxt@sidebase/nuxt-auth など)

プロジェクト作成と初期構造

新規プロジェクト(nuxi CLI)
# 対話形式で雛形生成(Bun / pnpm / npm / yarn から選択)
npx nuxi@latest init my-app
# ? Which package manager would you like to use? pnpm
# ? Initialize git repository? Yes
# ? Install dependencies? Yes

cd my-app
pnpm dev           # http://localhost:3000
pnpm build         # .output/ にビルド
pnpm preview       # 本番モードで起動

# モジュール追加(例: Tailwind CSS)
npx nuxi module add @nuxtjs/tailwindcss

Nuxt 4 の新しいディレクトリ構造

my-app/ の中身
my-app/
├── app/                    ← アプリケーションコードがここに集約(Nuxt 4 の新規則)
│   ├── assets/
│   ├── components/         ← Auto-import 対象
│   ├── composables/        ← Auto-import 対象
│   ├── layouts/
│   ├── middleware/
│   ├── pages/              ← File-based Routing
│   ├── plugins/
│   ├── utils/              ← Auto-import 対象
│   ├── app.vue             ← ルートコンポーネント
│   ├── app.config.ts       ← ランタイム設定
│   └── error.vue
├── server/                 ← サーバー / API コード(Nitro)
│   ├── api/
│   ├── routes/
│   ├── middleware/
│   └── utils/
├── shared/                 ← app/ と server/ の両方で使う型や定数
├── public/                 ← そのまま配信される静的ファイル
├── modules/                ← ローカルの Nuxt Module
├── nuxt.config.ts
├── package.json
└── tsconfig.json
なぜ app/ に分けたか: Nuxt 3 ではプロジェクトルートに components/ / pages/ / server/ / node_modules/ / 設定ファイル群が並列で存在し、ファイルウォッチャーがルート全体を監視するためWindows や WSL で劇的に遅くなる問題がありました。Nuxt 4 の app/ 分離はこの問題を根本解決し、IDE のインデックス速度も向上しています。

Pages と File-based Routing

pages ディレクトリとルーティング
app/pages/
├── index.vue               → /
├── about.vue               → /about
├── posts/
│   ├── index.vue           → /posts
│   ├── [id].vue            → /posts/:id
│   └── [...slug].vue       → /posts/* (catch-all)
├── users/
│   ├── [id]/
│   │   ├── index.vue       → /users/:id
│   │   └── settings.vue    → /users/:id/settings
└── (auth)/                 ← グループ(URL に含まれない)
    ├── login.vue           → /login
    └── register.vue        → /register
app/pages/posts/[id].vue ── 動的ルート
<script setup lang="ts">
// useRoute で params 取得(Auto-import なので import 不要)
const route = useRoute();
const id = computed(() => String(route.params.id));

// useFetch でサーバールートからデータ取得
const { data: post, pending, error } = await useFetch(`/api/posts/${id.value}`);

// <head> を設定(useHead も Auto-import)
useHead({
  title: () => post.value?.title ?? "読み込み中...",
  meta: [{ name: "description", content: () => post.value?.excerpt ?? "" }],
});
</script>

<template>
  <article v-if="post">
    <h1>{{ post.title }}</h1>
    <time>{{ new Date(post.publishedAt).toLocaleDateString() }}</time>
    <div v-html="post.html" />
  </article>
  <p v-else-if="pending">読み込み中...</p>
  <NuxtLink v-else to="/posts">一覧へ</NuxtLink>
</template>

Auto-imports ── import 不要の開発体験

Nuxt は決まった場所に置かれたコンポーネント・コンポーザブル・ユーティリティを自動で importします。Vue API(ref / computed / watch)・Nuxt API(useFetch / useHead / useState)も import 不要です。

app/composables/useCounter.ts ── 定義するだけで全ファイルから使える
// ファイル名がそのままコンポーザブル名になる(useCounter)
export const useCounter = (initial = 0) => {
  const count = ref(initial);
  const increment = () => (count.value += 1);
  const decrement = () => (count.value -= 1);
  return { count, increment, decrement };
};
どの .vue からでも import なしで使える
<script setup lang="ts">
const { count, increment } = useCounter(10);
</script>

<template>
  <button @click="increment">{{ count }}</button>
</template>

コンポーネントの Auto-import

app/components/ui/Button.vue を設置すると…
<!-- 別ファイルから <UiButton> として使える(ディレクトリ名 + ファイル名) -->
<template>
  <UiButton variant="primary" @click="save">保存</UiButton>
</template>
Auto-import を使わない書き方も可能: チーム規約で明示 import を好む場合は nuxt.config.tsimports: { autoImport: false } を設定すると明示 import 強制モードになります。Auto-import を使いつつ特定コンポーザブルだけ除外するなど細かな制御もできます。

useFetch / useAsyncData ── Nuxt 4 で改善されたデータフェッチ

Nuxt 4 では useFetchuseAsyncData が 4 つの重要な変更を受けました。

変更点 内容
同キー共有 ref 同じキーを使う複数コンポーネントが同一の data / error / status を共有する
shallowRef 既定 datashallowRef 型に。深い値の変更を検知したい場合は { deep: true } を付ける
既定値が undefined 初期状態の data / errornullundefined に変更
dedupe オプション true / false"cancel" / "defer" の文字列に変更
useFetch の典型パターン(SSR 対応)
<script setup lang="ts">
// キーを明示的に渡す(同キー共有の恩恵を受けるため)
const { data: posts, pending, error, refresh } = await useFetch("/api/posts", {
  key: "posts-list",
  default: () => [],                    // SSR 中も描画が崩れない
  transform: (res: any[]) => res.map(p => ({ ...p, isHot: p.likes > 100 })),
  watch: [() => route.query.category],  // クエリ変更時に再取得
});

// 深い反応性が必要な場合だけ deep: true
const { data } = await useFetch("/api/deeply-nested", { deep: true });

// dedupe は "cancel" / "defer"
await refresh({ dedupe: "cancel" });
</script>

useAsyncData ── 任意の非同期関数を key 付きで

app/composables/usePost.ts
export const usePost = (id: MaybeRefOrGetter<string>) => {
  return useAsyncData(
    () => `post-${toValue(id)}`,                // キー(同値なら共有される)
    () => $fetch(`/api/posts/${toValue(id)}`),  // $fetch は Nuxt の fetch ラッパ
    { watch: [() => toValue(id)] },
  );
};
$fetchuseFetch の使い分け: $fetch はただの fetch ラッパで、クライアントでもサーバーでも呼べるがリアクティブではないuseFetch は SSR ハイドレーション・キャッシュ共有・watch 再取得を含む Vue のリアクティブ API。ページの初期表示データには useFetch、ボタンクリック時の 1 回限りの API 呼び出しには $fetch を使うのが定石です。

Nitro サーバールート ── server/api と server/routes

Nuxt に組み込まれている Nitro は、server/api/**server/routes/** に置いた TS ファイルを自動的にエンドポイント化します。Node / Vercel / Cloudflare Workers / AWS Lambda / Bun / Deno など任意の実行先へ同じコードでデプロイできるのが最大の利点です。

API エンドポイント(server/api)

server/api/posts/index.get.ts ── GET /api/posts
export default defineEventHandler(async (event) => {
  const query = getQuery(event);
  const page  = Number(query.page ?? 1);

  const posts = await prisma.post.findMany({
    take: 20,
    skip: (page - 1) * 20,
    orderBy: { createdAt: "desc" },
  });

  return posts;
});
server/api/posts/index.post.ts ── POST /api/posts
import { z } from "zod";

const Body = z.object({
  title: z.string().min(1).max(80),
  body:  z.string().min(1),
});

export default defineEventHandler(async (event) => {
  const raw = await readBody(event);
  const parsed = Body.safeParse(raw);
  if (!parsed.success) {
    throw createError({ statusCode: 400, message: parsed.error.message });
  }
  const created = await prisma.post.create({ data: parsed.data });
  setResponseStatus(event, 201);
  return created;
});
server/api/posts/[id].get.ts ── 動的ルート
export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, "id");
  if (!id) throw createError({ statusCode: 400, message: "id required" });

  const post = await prisma.post.findUnique({ where: { id } });
  if (!post) throw createError({ statusCode: 404, message: "not found" });

  // キャッシュヘッダ
  setResponseHeader(event, "Cache-Control", "public, max-age=60");
  return post;
});
ファイル名の命名規則: [name].[method].ts で HTTP メソッド付き、省略すると全メソッド受付。[id] は動的パラメータ、[...slug] はキャッチオール。Nitro が JIT で解析するので手動のルーター定義は不要です。

任意 HTML / サーバーレスポンスを返す server/routes

server/routes/sitemap.xml.ts ── XML 配信
export default defineEventHandler(async (event) => {
  const posts = await prisma.post.findMany({ select: { id: true, updatedAt: true } });
  setResponseHeader(event, "content-type", "application/xml");

  return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  ${posts.map(p => `
    <url>
      <loc>https://example.com/posts/${p.id}</loc>
      <lastmod>${p.updatedAt.toISOString()}</lastmod>
    </url>`).join("")}
</urlset>`;
});

Layouts / Middleware / Plugins

Layouts

app/layouts/default.vue
<template>
  <div class="app-shell">
    <AppHeader />
    <main>
      <slot />           <!-- ページが埋め込まれる -->
    </main>
    <AppFooter />
  </div>
</template>
app/layouts/admin.vue を切り替え
<script setup lang="ts">
definePageMeta({ layout: "admin" });
</script>

<template>
  <h1>管理画面</h1>
</template>

Middleware(ルート単位の前処理)

app/middleware/auth.global.ts ── すべてのルートで実行
export default defineNuxtRouteMiddleware((to) => {
  const { user } = useUser();           // 自作 composable
  if (!user.value && to.path !== "/login") {
    return navigateTo("/login");
  }
});
特定ページのみ適用するミドルウェア
// app/middleware/admin.ts(named middleware)
export default defineNuxtRouteMiddleware((to) => {
  const { user } = useUser();
  if (!user.value?.isAdmin) {
    throw createError({ statusCode: 403, statusMessage: "Forbidden" });
  }
});
app/pages/admin/users.vue
<script setup lang="ts">
definePageMeta({ middleware: ["auth", "admin"] });
</script>

Plugins

app/plugins/dayjs.ts ── クライアント / サーバー両方で初期化
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";

export default defineNuxtPlugin(() => {
  dayjs.extend(relativeTime);
  return {
    provide: { dayjs },        // useNuxtApp().$dayjs で使える
  };
});

Nuxt Modules ── エコシステム

よく使うモジュール
# Tailwind CSS
npx nuxi module add @nuxtjs/tailwindcss

# 状態管理(Pinia)
npx nuxi module add @pinia/nuxt

# コンテンツ(Markdown ベース CMS)
npx nuxi module add @nuxt/content

# SEO / head 管理
npx nuxi module add @nuxtjs/seo

# 画像最適化
npx nuxi module add @nuxt/image

# 認証
npx nuxi module add @sidebase/nuxt-auth

# i18n
npx nuxi module add @nuxtjs/i18n

# DB 接続(Drizzle / Prisma は直接 server/ 配下に書くのが一般的)
npx nuxi module add @nuxt/db            # 実験的統合

Pinia で状態管理

app/stores/user.ts ── Composition API スタイル
import { defineStore } from "pinia";

export const useUserStore = defineStore("user", () => {
  const user = ref<{ id: string; name: string } | null>(null);
  const isAuthenticated = computed(() => !!user.value);

  async function login(email: string, password: string) {
    const res = await $fetch("/api/auth/login", {
      method: "POST",
      body: { email, password },
    });
    user.value = res.user;
  }

  function logout() { user.value = null; }

  return { user, isAuthenticated, login, logout };
});
ページから使う
<script setup lang="ts">
const userStore = useUserStore();
await userStore.login("alice@example.com", "pw");
</script>

<template>
  <p v-if="userStore.isAuthenticated">{{ userStore.user!.name }}さん</p>
</template>

TypeScript プロジェクト分割(Nuxt 4 の新機能)

Nuxt 4 は .nuxt/ 配下に4 つの別々の TypeScript プロジェクトを自動生成します。これにより、アプリ側で Node 固有型が出る・サーバー側で Vue 型が出る、といった混乱が根本解決しました。

tsconfig 対象
.nuxt/tsconfig.app.json app/ 配下のクライアント / ユニバーサルコード
.nuxt/tsconfig.server.json server/ 配下の Nitro サーバーコード
.nuxt/tsconfig.shared.json shared/ 配下(app/ と server/ の両方から参照)
.nuxt/tsconfig.node.json ビルド時ツール(nuxt.config.ts、ローカル modules)
tsconfig.json(ルート)── プロジェクト参照
{
  "references": [
    { "path": "./.nuxt/tsconfig.app.json" },
    { "path": "./.nuxt/tsconfig.server.json" },
    { "path": "./.nuxt/tsconfig.shared.json" },
    { "path": "./.nuxt/tsconfig.node.json" }
  ],
  "files": []
}

デプロイ ── 任意のプロバイダへ同じコード

Nitro は環境変数 NITRO_PRESET(または nitro.preset)で出力ターゲットを切り替えます。同じアプリコードが各プロバイダで動きます。

主要プロバイダへのデプロイコマンド
# Vercel(自動検出)
pnpm build
vercel deploy

# Cloudflare Workers
NITRO_PRESET=cloudflare_module pnpm build
npx wrangler deploy

# Netlify
NITRO_PRESET=netlify pnpm build

# Node.js サーバー(自前 VPS / Docker)
NITRO_PRESET=node-server pnpm build
node .output/server/index.mjs

# Bun で動かす
NITRO_PRESET=bun pnpm build
bun .output/server/index.mjs

# Deno Deploy
NITRO_PRESET=deno-deploy pnpm build
deployctl deploy .output/server/index.mjs

# AWS Lambda
NITRO_PRESET=aws-lambda pnpm build

# 完全静的(SSG)
pnpm generate
# .output/public/ を任意の静的ホスティングへ
Hybrid Rendering(ルート単位の描画戦略): nuxt.config.tsrouteRules を使うと、ルート単位で SSR / SSG / ISR / SPA / 404 を指定できます。「トップは SSG、ダッシュボードは SSR、管理画面は SPA」のような混在構成を 1 プロジェクトで実現できます。
routeRules ── ルート単位の戦略
export default defineNuxtConfig({
  routeRules: {
    "/":              { prerender: true },                    // SSG
    "/blog/**":       { isr: 3600 },                           // ISR(1 時間)
    "/dashboard/**":  { ssr: false },                          // SPA
    "/admin/**":      { ssr: true, robots: false },            // SSR(noindex)
    "/api/**":        { cors: true, headers: { "Cache-Control": "no-store" } },
  },
});

Nuxt 3 → 4 移行手順

移行は「段階的オプトイン → 自動 codemod → 個別修正」の 3 ステップで進めるのが安全です。

Step 1 ── Nuxt 3 で compatibilityVersion 4 を有効化

nuxt.config.ts
export default defineNuxtConfig({
  future: {
    compatibilityVersion: 4,    // v4 の挙動を事前テスト
  },
  // 旧挙動に戻したい項目があれば experimental で個別指定
  experimental: {
    pendingWhenIdle: true,                  // pending の旧挙動
    normalizeComponentNames: false,         // コンポーネント名正規化を無効化
    spaLoadingTemplateLocation: "within",   // SPA loading の旧位置
  },
});
この時点でテストを回して挙動差分を検出
pnpm dev
pnpm test
pnpm build

Step 2 ── Nuxt 4 にアップグレード

実際のアップグレード
# dedupe で依存重複を整理しつつ v4 安定版へ
npx nuxi upgrade --dedupe

# ディレクトリ構造を自動で app/ に移行
npx codemod@latest nuxt/4/file-structure

# その他の破壊的変更を自動修正
npx codemod@latest nuxt/4/default-data-error-value   # data/error 既定値
npx codemod@latest nuxt/4/deprecated-dedupe-value    # dedupe: true/false → "cancel"/"defer"
npx codemod@latest nuxt/4/shallow-function-reactivity

# すべて一度に
npx codemod@latest nuxt/4/migration-recipe

Step 3 ── 手動確認が必要な項目

  • data / error を参照している個所で初期値 null 前提のコードundefined に対応(if (data.value) で安全)
  • datashallowRef になったため、深いオブジェクトを直接書き換えている個所は { deep: true } を付けるか、data.value = { ...data.value, foo: x } のように差し替え
  • window.__NUXT__ を使っている場合は useNuxtApp().payload に書き換え
  • pages:extend フックを使うモジュールは pages:resolved に移行
  • Unhead v2 の API 変更(vmid プロパティ削除など)への対応

落とし穴と注意点

useFetch の data が shallowRef

Nuxt 4 の datashallowRefdata.value.items.push(x) のような深い変更は検出されません。素直に data.value = { ...data.value, items: [...data.value.items, x] } と差し替えるか、{ deep: true } オプションを付けます。

既定値が undefined になった副作用

const { data } = await useFetch(...) の直後に data.value.title とやるとTypeError(undefined のプロパティアクセス)。default: () => ({ title: "" }) を指定するか、data.value?.title に変更します。

app/ への移動を忘れる

Nuxt 4 にアップした後、古い位置にある components/ / pages/認識されません。codemod で自動移動されなかったファイル(手で置いたもの、動的生成したもの)は、自分で app/ に移動する必要があります。旧構造を維持したい場合のみ srcDir: "." を設定します。

サーバー専用モジュールをクライアントで import する事故

server/ 配下の型やユーティリティは、shared/ に置かない限り app/ からは参照できません(型エラー)。間違えて server/utils/db.tsapp/composables/ から import すると、ビルド時に Prisma や Node 組込みがクライアントに漏れ込む事故になります。TypeScript プロジェクト分割でこの事故が型エラーとして検出されるため、エラーが出たら構造を見直してください。

Auto-import による名前衝突

別ディレクトリに同名のコンポーネント(例: app/components/ui/Button.vueapp/components/form/Button.vue)があると、Auto-import 名は UiButton / FormButton とプリフィックス付きになります。Button で呼ぶと衝突警告が出るので、ディレクトリ構造で命名空間を分けるのが基本です。

SSR と onMounted の混同

SSR 時はサーバーで script setup が実行されますが、onMounted はクライアントでしか走りません。DOM に触れる処理を script setup に直接書くと SSR 時にエラーになります。ブラウザ API を使う処理は必ず onMounted 内、あるいは import.meta.client ガードを使います。

よくある質問

QNuxt と Next.js / SvelteKit / Astro はどう使い分けますか?
AVue が好きならほぼ Nuxt 一択です。React なら Next.js、Svelte なら SvelteKit、コンテンツ主体で軽量配信なら Astroが向きます。フレームワーク比較で悩む時は「チームの Vue / React / Svelte 経験値」と「必要なレンダリング戦略(SSR 重視か SSG 重視か Edge 重視か)」で決めるのが失敗しません。Vue 3 の学習なら TypeScript × Vue 3 Composition API 完全ガイド が参考になります。
QNuxt 3 と Nuxt 4 のどちらで始めるべきですか?
A2026 年 4 月時点では新規プロジェクトは Nuxt 4 一択です。移行コストの大半は自動 codemod で処理でき、TypeScript プロジェクト分割の恩恵は開発体験を大きく改善します。Nuxt 3 から既存プロジェクトを移行する場合も、future.compatibilityVersion: 4 で挙動を事前確認してから本移行するのが王道です。
QNitro はどこまで自由にサーバー処理を書けますか?
AExpress / Fastify で書けるほぼ全てのこと(HTTP ルート、ミドルウェア、WebSocket、Cron、Storage、Nitro Tasks)が可能です。特に強力なのは「コードを一切変えずに Vercel・Cloudflare Workers・AWS Lambda・Deno Deploy・Bun・Node 自前へデプロイ先を切り替えられる」点。ランタイム移植性は Hono と並んで最高峰です。Hono の詳細は TypeScript × Hono 完全ガイド を参照してください。
QNuxt で Supabase / Drizzle / Prisma は使えますか?
Aすべて問題なく使えます。server/ 配下で各クライアントを初期化し、API ルートから呼ぶのが基本パターンです。Supabase は @nuxtjs/supabase 公式モジュールで Auth・RLS 統合がしやすく、Drizzle は server/db.tsBun.sqlpostgres.js を繋いで使います。詳細は Claude Code × Supabase 完全ガイドTypeScript × Drizzle ORM 完全ガイド を参照。
QAuto-imports は本当に便利ですか? 逆に可読性が落ちませんか?
A大規模プロジェクトでは逆に「この関数どこから来た?」問題が起きやすいのは事実です。対策は 3 つ: ①VSCode の Volar / Vue Language Features 拡張でホバー時に定義元を表示、②ディレクトリ規約を徹底(utils/ にはピュア関数のみ、副作用は composables/)、③重要な public API だけ明示 import に切り替えimports: { dirs: [...], autoImport: "explicit" })。DX の恩恵が大きいため、規約整備で対応するのが現実解です。
QSSR と SPA と SSG はどのように選ぶべきですか?
ASEO が重要 + データが動的なら SSR、SEO が重要 + データが静的なら SSG、SEO 不要 + インタラクション重視なら SPA が基本。Nuxt 4 の routeRules なら「トップと記事は SSG、ダッシュボードは SPA」のような混在構成が 1 プロジェクトで可能です。Hybrid が取れるのが Nuxt(と Next.js)の強みです。
QBun や Deno で Nuxt を動かせますか?
A動かせます。ビルド・開発サーバーともに Bun / Deno 2 で動作確認されており、Nitro の bun / deno-deploy プリセットで本番デプロイも可能です。特に Bun は bun dev の起動が高速で、大規模 Nuxt プロジェクトで恩恵が大きいです。
QBiome は Nuxt プロジェクトで使えますか?
A使えます。Nuxt 4 は .vue ファイルを多用しますが、Biome の v2.3 で Vue 実験サポートが入ったため、biome.jsonfiles.includes**/*.vue を加えるだけで lint / format が動きます。ESLint + Prettier の Vue 設定より桁違いに高速なので、モノレポで採用する価値があります。

まとめ

  • Nuxt 4 が 2026 年の Vue フルスタック標準。app/ + server/ の明確な分離で IDE / ビルドが高速化
  • Auto-imports で components / composables / utils が import 不要。Vue / Nuxt API も自動
  • Nitro サーバーで任意プロバイダに同じコードでデプロイ。Vercel / Cloudflare / Netlify / Node / Bun / Deno すべて対応
  • useFetch / useAsyncData の改善: 同キー共有 ref / shallowRef 既定 / undefined 既定 / dedupe 文字列化
  • routeRules でルート単位の SSR / SSG / ISR / SPA 混在が可能
  • TypeScript プロジェクト分割(app / server / shared / node)で型事故を静的検出
  • Nuxt 3 → 4 移行は compatibilityVersion 4 で事前検証 → codemod で自動修正 → 手動個別対応の 3 ステップ
  • 200+ モジュールで Tailwind / Pinia / Content / Image / Auth / i18n / SEO 等が 1 コマンドで統合

Vue 3 Composition API の基礎は TypeScript × Vue 3 Composition API 完全ガイド、React / Svelte / Astro との選定は React 19 完全ガイドSvelte 5 完全ガイドAstro 完全ガイド、ランタイム選択は Bun 完全ガイドDeno 2 完全ガイド、バックエンド API は TypeScript × Hono 完全ガイド、DB は TypeScript × Drizzle ORM 完全ガイド、BaaS は Claude Code × Supabase 完全ガイド、DevTool は Biome 完全ガイド もあわせて、Nuxt 4 を核に据えた 2026 年型 Vue フルスタック構成を組み上げてください。