Nuxt の使い方 — Vue.js ベースのフルスタックフレームワーク完全ガイド
一言でいうと
Nuxtは、Vue.jsをベースにしたフルスタックWebアプリケーションフレームワークです。SSR・SSG・ハイブリッドレンダリングを備え、ファイルベースルーティング・自動インポート・TypeScriptゼロ設定など、プロダクションレディなWebアプリを高速に構築するための仕組みが一通り揃っています。
どんな時に使う?
- SEOが重要なWebサイト・メディアサイト — SSR/SSGによりクローラーに最適化されたHTMLを配信でき、
useSeoMetaなどのビルトインAPIでメタタグ管理も容易です - フルスタックアプリケーション —
server/ディレクトリにAPIエンドポイントを定義でき、フロントエンドとバックエンドを1つのリポジトリで完結させたい場合に最適です - 大規模なVue.jsプロジェクト — ファイルベースルーティング、自動コード分割、レイアウトシステム、モジュールエコシステムにより、チーム開発でも規約に沿った統一的なアーキテクチャを維持できます
インストール
新規プロジェクトの作成(推奨)
# npm
npx nuxi@latest init my-app
# pnpm
pnpm dlx nuxi@latest init my-app
# yarn
yarn dlx nuxi@latest init my-app
もしくは create コマンドでも作成できます。
npm create nuxt@latest my-app
既存プロジェクトへの追加
# npm
npm install nuxt
# yarn
yarn add nuxt
# pnpm
pnpm add nuxt
注意: 本記事はNuxt 4.x(v4.4.2)を前提としています。Nuxt 3.xとは一部APIや挙動が異なる場合があります。
基本的な使い方
プロジェクト構成
Nuxtプロジェクトの最小構成は以下のとおりです。
my-app/
├── app/
│ ├── app.vue # ルートコンポーネント
│ ├── pages/ # ファイルベースルーティング
│ │ ├── index.vue
│ │ └── about.vue
│ ├── components/ # 自動インポートされるコンポーネント
│ ├── composables/ # 自動インポートされるComposable
│ └── layouts/ # レイアウト定義
├── server/ # サーバーAPI
│ └── api/
│ └── hello.ts
├── public/ # 静的ファイル
├── nuxt.config.ts # Nuxt設定ファイル
└── package.json
補足: Nuxt 4ではアプリケーションコードが
app/ディレクトリ配下に移動しました。Nuxt 3からの移行時はこの点に注意してください。
app.vue(エントリーポイント)
<script setup lang="ts">
useSeoMeta({
title: 'My Nuxt App',
description: 'Nuxtで構築したWebアプリケーション',
})
</script>
<template>
<div>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</div>
</template>
ページコンポーネント(pages/index.vue)
<script setup lang="ts">
// useFetchは自動インポートされる(importの記述不要)
const { data: posts, status } = await useFetch('/api/posts')
</script>
<template>
<div>
<h1>記事一覧</h1>
<p v-if="status === 'pending'">読み込み中...</p>
<ul v-else>
<li v-for="post in posts" :key="post.id">
<NuxtLink :to="`/posts/${post.id}`">
{{ post.title }}
</NuxtLink>
</li>
</ul>
</div>
</template>
サーバーAPI(server/api/posts.ts)
export default defineEventHandler(async (event) => {
// Nitroサーバーエンジン上で動作する
return [
{ id: 1, title: 'Nuxt入門' },
{ id: 2, title: 'Vue 3の新機能' },
{ id: 3, title: 'TypeScript活用術' },
]
})
開発サーバーの起動
npx nuxt dev
http://localhost:3000 でアプリケーションが起動します。
よく使うAPI — Nuxt の主要機能の使い方
1. useFetch — データ取得
SSR対応のデータフェッチComposableです。サーバーサイドで取得したデータをクライアントにシリアライズして渡すため、ハイドレーション時の二重リクエストが発生しません。
<script setup lang="ts">
interface User {
id: number
name: string
email: string
}
// 型パラメータで戻り値の型を指定可能
const { data, status, error, refresh } = await useFetch<User[]>('/api/users', {
// クエリパラメータ(リアクティブ対応)
query: { role: 'admin' },
// レスポンスの変換
transform: (users) => users.filter((u) => u.id > 0),
})
// 手動でデータを再取得
async function handleRefresh() {
await refresh()
}
</script>
<template>
<div>
<p v-if="status === 'pending'">読み込み中...</p>
<p v-else-if="error">エラー: {{ error.message }}</p>
<ul v-else>
<li v-for="user in data" :key="user.id">{{ user.name }}</li>
</ul>
<button @click="handleRefresh">更新</button>
</div>
</template>
2. useAsyncData — 柔軟なデータ取得
useFetch よりも汎用的なデータ取得Composableです。任意の非同期関数を渡せます。
<script setup lang="ts">
const { data: config } = await useAsyncData('app-config', async () => {
// 複数のAPIを並列で呼び出す
const [settings, features] = await Promise.all([
$fetch('/api/settings'),
$fetch('/api/features'),
])
return { settings, features }
}, {
// サーバーサイドでのみ実行
server: true,
// 5分間キャッシュ
getCachedData(key, nuxtApp) {
const cached = nuxtApp.payload.data[key]
if (cached) return cached
return null
},
})
</script>
3. useState — SSR対応のリアクティブ状態管理
サーバーサイドからクライアントサイドへ安全にシリアライズされるグローバルな状態管理です。
// composables/useCounter.ts
export function useCounter() {
// キーを指定してグローバルな状態を作成
const count = useState<number>('counter', () => 0)
function increment() {
count.value++
}
function decrement() {
count.value--
}
return { count, increment, decrement }
}
<script setup lang="ts">
// どのコンポーネントからでも同じ状態を参照できる
const { count, increment, decrement } = useCounter()
</script>
<template>
<div>
<p>カウント: {{ count }}</p>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>
4. useSeoMeta / useHead — SEO・メタタグ管理
<script setup lang="ts">
// 型安全なメタタグ設定(推奨)
useSeoMeta({
title: '記事タイトル',
ogTitle: '記事タイトル',
description: '記事の説明文です。',
ogDescription: '記事の説明文です。',
ogImage: 'https://example.com/og-image.png',
twitterCard: 'summary_large_image',
})
// より細かい制御が必要な場合
useHead({
htmlAttrs: { lang: 'ja' },
link: [
{ rel: 'canonical', href: 'https://example.com/posts/1' },
],
script: [
{ type: 'application/ld+json', innerHTML: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Article',
headline: '記事タイトル',
}) },
],
})
</script>
5. defineEventHandler / サーバーAPI — フルスタック開発
Nuxtのサーバーエンジン(Nitro)を使ったAPI定義です。
// server/api/posts/[id].get.ts
// ファイル名の [id] が動的パラメータ、.get がHTTPメソッドに対応
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id')
// バリデーション
if (!id || isNaN(Number(id))) {
throw createError({
statusCode: 400,
statusMessage: 'Invalid post ID',
})
}
// DBやORMからデータ取得(例: Drizzle, Prismaなど)
const post = await getPostById(Number(id))
if (!post) {
throw createError({
statusCode: 404,
statusMessage: 'Post not found',
})
}
return post
})
// server/api/posts.post.ts
// POSTリクエスト用のハンドラ
export default defineEventHandler(async (event) => {
const body = await readBody<{ title: string; content: string }>(event)
if (!body.title || !body.content) {
throw createError({
statusCode: 422,
statusMessage: 'Title and content are required',
})
}
const post = await createPost(body)
return post
})
補足: nuxt.config.ts の主要設定
// nuxt.config.ts
export default defineNuxtConfig({
// 開発ツール
devtools: { enabled: true },
// モジュール
modules: [
'@nuxt/ui',
'@nuxt/image',
'@pinia/nuxt',
'@nuxtjs/i18n',
],
// ランタイム設定(環境変数の注入)
runtimeConfig: {
// サーバーサイドのみ(NUXT_SECRET_KEY 環境変数で上書き可能)
secretKey: '',
// クライアントにも公開される(NUXT_PUBLIC_API_BASE で上書き可能)
public: {
apiBase: 'https://api.example.com',
},
},
// レンダリングモードのルートごとの設定
routeRules: {
'/': { prerender: true }, // ビルド時に静的生成
'/dashboard/**': { ssr: false }, // SPAモード
'/api/**': { cors: true }, // CORS有効
'/blog/**': { isr: 3600 }, // ISR(1時間キャッシュ)
},
// TypeScript設定
typescript: {
strict: true,
},
})
類似パッケージとの比較
| 特徴 | Nuxt | Next.js | Remix | Astro |
|---|---|---|---|---|
| ベースフレームワーク | Vue.js | React | React (React Router) | 独自(マルチFW対応) |
| レンダリング | SSR / SSG / ISR / SPA | SSR / SSG / ISR / SPA | SSR / SPA | SSG中心 / SSR対応 |
| ファイルベースルーティング | ✅ | ✅ | ✅ | ✅ |
| 自動インポート | ✅(コンポーネント・Composable) | ❌ | ❌ | ❌ |
| サーバーエンジン | Nitro | Node.js / Edge | Node.js / Edge | 独自 |
| TypeScript | ゼロ設定 | ゼロ設定 | ゼロ設定 | ゼロ設定 |
| モジュールエコシステム | 300+モジュール | npmベース | npmベース | Integrations |
| デプロイ先 | Vercel / Cloudflare / AWS等 | Vercel最適化 / 他対応 | 各種対応 | 各種対応 |
| 学習コスト | 中(Vue経験者は低) | 中(React経験者は低) | 中 | 低 |
選定の指針:
- Vue.jsチーム → Nuxt一択
- Reactチーム → Next.js or Remix
- コンテンツ中心のサイト → Astroも有力な選択肢
- フルスタックを1リポジトリで → Nuxt / Next.js
注意点・Tips
1. useFetch と $fetch の使い分け
<script setup lang="ts">
// ✅ ページ/コンポーネントの初期データ取得 → useFetch
const { data } = await useFetch('/api/posts')
// ✅ ユーザー操作に応じたリクエス