nuxt の使い方

Nuxt is a free and open-source framework with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with Vue.js.

v4.4.21.4M/週MITフレームワーク
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

Nuxt の使い方 — Vue.js ベースのフルスタックフレームワーク完全ガイド

一言でいうと

Nuxtは、Vue.jsをベースにしたフルスタックWebアプリケーションフレームワークです。SSR・SSG・ハイブリッドレンダリングを備え、ファイルベースルーティング・自動インポート・TypeScriptゼロ設定など、プロダクションレディなWebアプリを高速に構築するための仕組みが一通り揃っています。

どんな時に使う?

  1. SEOが重要なWebサイト・メディアサイト — SSR/SSGによりクローラーに最適化されたHTMLを配信でき、useSeoMeta などのビルトインAPIでメタタグ管理も容易です
  2. フルスタックアプリケーションserver/ ディレクトリにAPIエンドポイントを定義でき、フロントエンドとバックエンドを1つのリポジトリで完結させたい場合に最適です
  3. 大規模な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,
  },
})

類似パッケージとの比較

特徴NuxtNext.jsRemixAstro
ベースフレームワークVue.jsReactReact (React Router)独自(マルチFW対応)
レンダリングSSR / SSG / ISR / SPASSR / SSG / ISR / SPASSR / SPASSG中心 / SSR対応
ファイルベースルーティング
自動インポート✅(コンポーネント・Composable)
サーバーエンジンNitroNode.js / EdgeNode.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')

// ✅ ユーザー操作に応じたリクエス

比較記事