Contents
1. Nuxt のレンダリングモードとは
Nuxt は SSR(サーバーサイドレンダリング)・SSG(静的サイト生成)・SPA(シングルページアプリケーション) の 3 種類のレンダリング方式を公式に提供しています。
このセクションではそれぞれのモードがどのような仕組みで動作し、プロジェクト要件とどう照らし合わせるべきかを概観します。
1.1 SSR(Server‑Side Rendering)
SSR はリクエスト受信時にサーバー側で Vue コンポーネントを HTML に変換し、完成したページをクライアントへ返す方式です。
- メリット
- 初回表示が高速(HTML が即座に描画)
- SEO フレンドリー:検索エンジンは完全な DOM を取得できる
-
認証情報やユーザー固有データをサーバー側で安全に組み込める
-
デメリット
- サーバーレスポンスが毎回必要になるため、インフラ負荷が高くなる可能性がある
- ビルド時点ではページが確定しないので、静的キャッシュの活用は限定的
詳細は公式ガイド「Rendering Modes – SSR」を参照してください。
1.2 SSG(Static Site Generation)
SSG はビルド時に全ページまたは一部ページを事前に HTML として生成し、CDN 経由で配信します。
- メリット
- CDN が高速かつ安定した配信を担保できるため、トラフィックが急増してもコストが抑えやすい
-
ビルド成果物は純粋な静的ファイルなので、サーバー管理が不要
-
デメリット
- データ更新時に再ビルドが必要になるため、頻繁に変わるコンテンツには不向き
- ユーザー固有情報(認証後のページなど)は SSR と組み合わせないと実装できない
詳細は公式ガイド「Rendering Modes – SSG」をご覧ください。
1.3 SPA(Single‑Page Application)
SPA はクライアント側だけで全てのレンダリングを行い、サーバーは純粋な API エンドポイントとして機能します。
- メリット
- フロントエンド開発がシンプルになり、コード分割やホットリロードがそのまま活かせる
-
バックエンドに依存しないため、サーバーレス環境へのデプロイが容易
-
デメリット
- 初回ロード時に JavaScript が必須になるので、SEO とファーストビュー速度が劣化する
- 大規模アプリではクライアント側のメモリ使用量が増大しやすい
詳細は公式ガイド「Rendering Modes – SPA」で確認できます。
2. プロジェクトに最適なレンダリングモードの選び方
このセクションでは Learn Nuxt の推奨基準 を元に、実際の要件と照らし合わせてどのモードがベストかを判断する手順を示します。
参照 URL: https://learn.nuxt.com/guide/rendering-modes#selection
2.1 判定基準表(Learn Nuxt が示す指針)
| 判定項目 | 推奨モード | 補足説明 |
|---|---|---|
| SEO が必須/検索エンジンでインデックスしたい | SSR または SSG | 検索ロボットが HTML を直接取得できる点が重要 |
| コンテンツ更新頻度が高く、ユーザーごとに異なる情報を表示する必要がある | SSR | サーバー側でリクエスト時にデータ注入が可能 |
| ページ構成がほぼ固定でトラフィック予測ができる(ブログ・ドキュメント) | SSG | ビルド時に生成した静的ファイルを CDN 配信すればコスト最適化 |
| 社内ツールや管理画面など、検索対象外でインタラクティブさだけが求められる | SPA | クライアント側だけで完結できるので実装がシンプル |
2.2 選択フローの具体例
- SEO が必要か? → 必要なら次は「データの動的性」へ。
- ページごとにユーザー固有情報があるか? → あれば SSR、なければ SSG。
- 更新頻度は? → 週単位以上であれば SSR、数日~月単位なら SSG。
このフローを踏むことで、要件とコスト・パフォーマンスのバランスが取れたモード選択が可能です。
3. Nuxt 3 プロジェクトで SSR を有効化する手順
以下は 最新安定版(2026 年予測 v3.13 系) の CLI と設定ファイルを前提にした、SSR アプリの作成・検証フローです。
設定例は公式リファレンス https://nuxt.com/docs/api/configuration/nuxt-config に沿っています。
3.1 プロジェクトの作成
|
1 2 3 4 5 6 7 |
# 任意のディレクトリで新規 Nuxt アプリを初期化 npx nuxi init my-ssr-app cd my-ssr-app # 推奨は pnpm、npm・yarn でも可 pnpm install # または npm i / yarn |
nuxi init は nuxt@latest(2026 年時点では v3.13)を取得し、以下のファイル構成を自動生成します。
nuxt.config.tspages/app.vueなどの基本テンプレート
3.2 nuxt.config.ts に SSR を明示
デフォルトテンプレートでは SSR が有効(ssr: true)になっていますが、過去のバージョンと混在した設定が残ることがあります。以下は最新構文に合わせたサンプルです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// nuxt.config.ts import { defineNuxtConfig } from 'nuxt/config' export default defineNuxtConfig({ // ---- レンダリングモード ------------------------------------------------- ssr: true, // SSR を必ず有効化 // ---- Nitro のビルドターゲット ----------------------------------------- nitro: { // Vercel にデプロイしたい場合は 'vercel'、Netlify Edge は 'netlify-edge' preset: 'node-server', // ローカル開発・Node デプロイ時のデフォルト devServer: { // 開発サーバーのポートカスタマイズ例 port: Number(process.env.PORT) || 3000, }, compressPublicAssets: true, // Gzip/Brotli 圧縮を自動適用(最新でも有効) }, // ---- Runtime Config ---------------------------------------------------- runtimeConfig: { apiSecret: process.env.API_SECRET, // ← サーバー側のみ参照できる秘密鍵 public: { apiBase: process.env.NUXT_PUBLIC_API_BASE || 'https://api.example.com', }, }, }) |
nitro.presetの最新一覧は公式ドキュメント https://nuxt.com/docs/api/configuration/nitro#preset を参照してください。
3.3 SSR が動作しているかの確認
|
1 2 |
pnpm dev # または npm run dev |
ブラウザで http://localhost:3000 にアクセスし、「View Page Source」 で <html> 内にサーバー生成されたマークアップが存在すれば SSR が有効です。クライアント側だけの SPA だった場合は空の <div id="__nuxt"> のみが表示されます。
4. Nitro サーバーと SSR 環境の基礎
Nuxt 3 は内部で Nitro と呼ばれる軽量サーバーランタイムを使用しています。ここでは Nitro の役割、デフォルト設定、そして動的ルーティングや認証ミドルウェアの実装例を示します。
4.1 Nitro の主な機能とデフォルト
| 項目 | デフォルト(2026 年予測) |
|---|---|
| ビルドターゲット | node-server(ローカル開発・汎用 Node.js) |
| ポート | 環境変数 PORT が無い場合は 3000 |
| 静的アセット出力先 | .output/public/ |
| 圧縮ミドルウェア | compressPublicAssets: true で自動有効化 |
Nitro は API ディレクトリ (server/api) の自動エクスポート、サーバーミドルウェア、そしてプラットフォーム別ビルド(Vercel, Netlify Edge, Cloudflare Workers 等)をシームレスに切り替える機構です。
4.2 動的ページと API エンドポイントの実装例
4.2.1 動的ページ (pages/users/[id].vue)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<!-- pages/users/[id].vue --> <script setup lang="ts"> import { useRoute, useAsyncData } from '#app' const route = useRoute() const { data: user } = await useAsyncData('user-' + route.params.id, () => $fetch(`/api/users/${route.params.id}`) ) </script> <template> <section v-if="user"> <h1>{{ user.name }}</h1> <p>{{ user.bio }}</p> </section> <p v-else>Loading…</p> </template> |
4.2.2 API エンドポイント (server/api/users/[id].ts)
|
1 2 3 4 5 6 7 8 9 10 11 |
// server/api/users/[id].ts export default defineEventHandler(async (event) => { const { id } = event.context.params! // ← 実際は DB 呼び出し等を行うが、例示のため固定データを返す return { id, name: 'John Doe', bio: 'Nuxt 開発者' } }) |
4.2.3 グローバル認証ミドルウェア (server/middleware/auth.global.ts)
|
1 2 3 4 5 6 7 8 |
// server/middleware/auth.global.ts export default defineEventHandler((event) => { const token = getHeader(event, 'authorization') if (!token || !validateToken(token)) { throw createError({ statusCode: 401, statusMessage: 'Unauthorized' }) } }) |
- ファイル名に
.global.が入っていると 全リクエスト に自動適用されます(SSR 時も同様)。 validateTokenはプロジェクト独自実装の関数です。テスト環境ではモック化すると便利です。
5. 環境変数と runtimeConfig の安全な取り扱い
SSR アプリでは「サーバーだけが知って良いシークレット」と「クライアントでも必要な公開設定」を厳密に分離することがセキュリティの基本です。Nuxt 3 はこの管理を runtimeConfig で統一的に行います。
5.1 private と public の違い
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// nuxt.config.ts(抜粋) export default defineNuxtConfig({ runtimeConfig: { // ← サーバー側専用。ビルド時にクライアントバンドルへ埋め込まれない apiSecret: process.env.API_SECRET, public: { // ← クライアントでも参照可能な設定 apiBase: process.env.NUXT_PUBLIC_API_BASE || 'https://api.example.com' } } }) |
- private(デフォルト):
useRuntimeConfig()の直下で取得。クライアント側のコードからはアクセスできません。 - public:
useRuntimeConfig().public経由で SSR・CSR 両方から参照可能。
5.2 .env ファイルの活用
プロジェクト根ディレクトリに .env を置くと、Nuxt が自動的に process.env にマッピングします。必ず .gitignore に追加し、機密情報がリポジトリへ流出しないようにしましょう。
|
1 2 3 4 |
# .env(例) API_SECRET=super-secret-key-12345 NUXT_PUBLIC_API_BASE=https://api.myapp.com |
5.3 コンポーザブルでの利用例
|
1 2 3 4 5 6 7 8 9 10 |
// composables/useApi.ts export const useApi = () => { const config = useRuntimeConfig() return $fetch.create({ baseURL: config.public.apiBase, // サーバー側だけで実行されるので secret が安全に渡せる headers: { Authorization: `Bearer ${config.apiSecret}` } }) } |
- クライアントコード では
apiSecretが自動的に除外され、ビルドサイズが肥大化しません。 - サーバー側(API ハンドラや Nitro Middleware) では
config.apiSecretが利用可能です。
6. デプロイとパフォーマンス最適化
SSR アプリを本番環境へデプロイする際の手順、プラットフォーム別の留意点、および実運用で役立つパフォーマンスチューニング手法をまとめます。
6.1 主なホスティング先と Nitro プリセット設定例
| プラットフォーム | ビルドコマンド | nitro.preset 設定例 |
デプロイスクリプト |
|---|---|---|---|
| Node.js(自前サーバ) | pnpm run build (.output/server/index.mjs が生成) |
'node-server' (デフォルト) |
bash<br># pm2 永続起動例<br>pm2 start .output/server/index.mjs --name my-ssr-app<br> |
| Vercel | pnpm run build(Vercel が自動実行) |
'vercel' |
vercel.json にビルド設定を追加 json<br>{ "builds": [{ "src": "nuxt.config.ts", "use": "@vercel/node" }] }<br> |
| Netlify Edge Functions | pnpm run build && pnpm generate(Edge 用に生成) |
'netlify-edge' |
netlify.toml の例 toml<br>[build]\n command = "pnpm run build"\n publish = ".output/public"\n\n[[edge_functions]]\n path = "/*"\n function = "server" # Nitro が生成した Edge Function 名\n |
各プラットフォームの最新プリセット一覧は https://nuxt.com/docs/api/configuration/nitro#preset を参照してください。
6.2 パフォーマンス最適化ポイント
6.2.1 キャッシュヘッダー
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
export default defineNitroPlugin((nitro) => { nitro.hooks.hook('request', (event) => { if (event.path.startsWith('/_nuxt/')) { // 静的アセットは長期キャッシュ setResponseHeader(event, 'Cache-Control', 'public, max-age=31536000, immutable') } else { // 動的ページは CDN 用に短めのキャッシュと stale-while-revalidate を設定 setResponseHeader(event, 'Cache-Control', 's-maxage=60, stale-while-revalidate=30') } }) }) |
6.2.2 Payload 圧縮
Nitro の compressPublicAssets: true が有効な場合、リクエストヘッダーに Accept-Encoding: gzip, br があると自動で Gzip/Brotli 圧縮が適用されます。特別な設定は不要ですが、CDN が圧縮を上書きしないようにオリジン側のヘッダーを保持してください。
6.2.3 Lazy‑load コンポーネント
|
1 2 3 4 5 6 |
import { defineAsyncComponent } from 'vue' const HeavyChart = defineAsyncComponent(() => import('~/components/HeavyChart.vue') ) |
- SSR 時は
defineAsyncComponentが サーバー側で先にレンダリング し、クライアントには遅延ロード用のプレースホルダーが送られます。 - 大容量の UI ライブラリ(例:Chart.js, Mapbox)を遅延させると FCP が顕著に改善します。
6.3 よくある設定ミスと対処法
| 症状 | 主な原因 | 確認・修正ポイント |
|---|---|---|
| 空白ページ(HTML が無い) | ssr: false が残っている、もしくは Nitro ビルド失敗 |
nuxt.config.ts → ssr を再確認し、pnpm run build のログにエラーが無いかチェック |
500 エラー + undefined |
環境変数未設定で runtimeConfig.private が undefined |
.env が正しくロードされたか (console.log(process.env)) を確認し、apiSecret のフォールバックを設定 |
| Vercel デプロイ時 “No route matches” | nitro.preset がデフォルトの node-server になっている |
nuxt.config.ts → nitro.preset = 'vercel' を明示し、再ビルド |
| Edge Functions で “Response size exceeds limit” | 圧縮が無効、または大きな画像・JSON がそのまま返却されている | compressPublicAssets: true の有無と Cache-Control 設定を見直し、必要ならストリーミングや分割送信に切り替える |
クライアント側で apiSecret が露出 |
runtimeConfig.public に誤ってシークレットを書いた |
nuxt.config.ts の構造を再確認し、シークレットは必ずトップレベル(private)へ配置 |
Nitro のデバッグモードは環境変数
NUXT_DEBUG=1で有効化できます。エラーログは.output/server/index.mjsのスタックトレースと合わせて確認してください。
7. まとめ
- SSR・SSG・SPA はそれぞれメリット/デメリットが明確で、要件に応じた選択が重要です。
- Learn Nuxt が提示する選定基準 を踏まえて、SEO 必須かつユーザー固有情報がある場合は SSR、コンテンツが固定で大量トラフィックが予想されるなら SSG、といった指針を活用しましょう。
- SSR 有効化手順 は
nuxt.config.tsのssr: trueと Nitro プリセットの設定だけで完了し、npm run devで「View Page Source」確認が最も手軽です。 - Nitro が提供する API 自動エクスポート・ミドルウェア・プラットフォーム別ビルドは、デプロイ先を意識した
preset設定と組み合わせるだけでシームレスに機能します。 - runtimeConfig による環境変数管理は、サーバー側シークレットとクライアント公開設定の分離を保証し、セキュリティリスクを低減します。
- デプロイ・パフォーマンス最適化 ではキャッシュヘッダー、圧縮、遅延ロードを組み合わせることで、SSR アプリでも高速かつスケーラブルなユーザー体験が実現できます。
本稿の設定例は「2026 年予測」に基づくものであり、公式ドキュメント(nuxt.com / learn.nuxt.com)と照らし合わせて最新情報を必ず確認してください。
参考リンク
| 内容 | URL |
|---|---|
| Nuxt 公式ドキュメント(設定リファレンス) | https://nuxt.com/docs/api/configuration/nuxt-config |
| Rendering Modes – Learn Nuxt | https://learn.nuxt.com/guide/rendering-modes |
| Nitro プリセット一覧 | https://nuxt.com/docs/api/configuration/nitro#preset |
| Runtime Config の使い方 | https://nuxt.com/docs/guide/going-further/runtime-config |
| Vercel デプロイガイド(Nuxt) | https://vercel.com/integrations/nuxt |
| Netlify Edge Functions との連携 | https://docs.netlify.com/functions/edge-functions/ |