ウェブエンジニア問題集
第13章

Next.jsのデプロイ — VercelとCloudflare Workersの違いを理解する

24
この章の目次開く

ここまでで、ページ、Route HandlersProxyServer Actions まで一通り扱いました。最後に必要なのが、作ったNext.jsアプリを本番環境へデプロイすることです。

Next.jsはVercel製のフレームワークですが、Vercelでしか動かないわけではありません。Node.jsサーバー、Docker、静的ホスティング、Cloudflare Workersなど、複数の選択肢があります。ただし、使える機能や必要な設定はデプロイ先によって変わります。

学習者学習者

Next.jsってVercelにデプロイするもの、という印象があるけど、Cloudflareや普通のサーバーでも動かせるの?

先生先生

動かせるよ。ただしVercelはNext.js向けに最適化されていて、Cloudflare Workersのようなエッジ環境ではOpenNext adapterなど追加の工程が必要になる。違いを理解して選ぼう。

Next.jsアプリを本番環境へデプロイしているイメージ


Next.jsのデプロイ先の全体像

Next.js公式では、主なデプロイ形態として Node.jsサーバー、Docker、static export、Adapterによる各プラットフォーム対応 が示されています。

デプロイ先向いているケース注意点
VercelNext.jsを最短で本番公開したいVercelの料金・制限・運用ルールを理解する
Node.jsサーバーVPS、Render、Railway、社内基盤などで動かしたいプロセス管理、ログ、スケールを自分で考える
DockerCloud Run、ECS、Kubernetesなどに載せたいコンテナ設計と環境変数管理が必要
static export完全な静的サイトとして配信したいSSR、Route Handlers、Server Actionsなどは使えない
Cloudflare Workersエッジ寄りの環境で配信したいOpenNext adapter、Wrangler、workerd での確認が必要

Vercelにデプロイする基本の流れ

Vercelでのデプロイは、GitHubなどのリポジトリを連携するのが最も一般的です。

最小限の流れは次のとおりです。

  1. GitHubにNext.jsプロジェクトをpushする
  2. Vercelで「New Project」からリポジトリを選ぶ
  3. Framework PresetがNext.jsになっていることを確認する
  4. 必要な環境変数を設定する
  5. Deployする

VercelはNext.jsプロジェクトを自動判定し、npm run build 相当のビルドを実行します。Vercel公式の Next.js on Vercel でも、Vercelへのデプロイはゼロ設定で、スケーラビリティ・可用性・グローバルパフォーマンス面の追加最適化があると説明されています。


Vercelで特に楽になること

VercelはNext.jsの開発元が提供するプラットフォームなので、Next.jsの機能とかなり密に統合されています。

機能Vercelで楽になる理由
Preview DeploymentPull Requestごとに確認URLができる
Production Deploymentmainブランチへの反映を本番公開にしやすい
SSRVercel Functionsとして自動的に実行される
StreamingRoute Handlers、Vercel Functions、React Server Componentsで扱いやすい
Image Optimizationnext/image の最適化を追加サービスなしで使いやすい
Cache-Control / ISRNext.jsのキャッシュ戦略とVercel CDNがつながりやすい
環境変数Production / Preview / Developmentで分けて管理できる
ロールバック過去のDeploymentへ戻しやすい

データ取得とキャッシュ で扱った静的レンダリング、再検証、キャッシュの考え方は、デプロイ先のCDNやランタイムと密接に関係します。Vercelではこの接続がNext.js向けに設計されているため、最初のデプロイ先として選びやすいです。


Vercelでしかできないことはあるのか

結論から言うと、Next.jsの基本機能そのものがVercelでしか使えない、というわけではありません。Node.jsサーバーやDockerでもNext.jsは動きます。

ただし、Vercelには「Vercelのプラットフォーム機能」として使えるものがあります。

分類Vercel以外ではどうなるか
デプロイ体験Git連携、Preview URL、Production昇格各プラットフォームやCI/CDで自分で構成する
Vercel CDNISR、Cache-Control、画像最適化との統合CDNや画像基盤を別途設計する
Vercel FunctionsSSRやRoute Handlerの実行基盤Node.jsサーバー、Lambda、Workersなど別ランタイムに載せる
Observabilityログ、メトリクス、Web Vitals系の統合Datadog、Sentry、Cloudflare Analyticsなどを選ぶ
Vercel固有サービスBlob、KV、Postgres、Edge Configなど他社DBやストレージで代替する

つまり、「VercelでしかNext.jsをデプロイできない」のではなく、VercelではNext.js向けの周辺機能が最初からつながっていると考えるのが正確です。

Vercel以外に出す場合は、Next.jsの機能をそのプラットフォームのビルド・キャッシュ・ランタイムへどう対応させるかを確認する必要があります。

Node.jsサーバーやDockerにデプロイする場合

Next.jsはNode.jsサーバーとして起動できます。package.json に次のようなスクリプトがあれば、本番用ビルドと起動ができます。

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}
json
npm run build
npm run start
bash

この形は、VPS、Render、Railway、Fly.io、社内のNode.js実行基盤などに向いています。Docker化する場合は、next.config.tsoutput: 'standalone' を設定して、実行に必要なファイルだけをまとめる構成がよく使われます。

// next.config.ts
import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  output: 'standalone',
};
 
export default nextConfig;
ts

standaloneとは何か

standalone は、Next.jsアプリを Node.jsサーバーとして本番実行するために必要なファイルだけをまとめる出力形式 です。

通常のプロジェクトには、ソースコード、開発用パッケージ、ビルドツール、テスト関連ファイルなど、本番起動には不要なものも多く含まれています。Next.js公式の output 設定 でも説明されているように、output: 'standalone' を有効にすると、next build 時にNext.jsが各ページやRoute Handlerの依存関係を解析し、実行に必要なファイルだけを .next/standalone にコピーします。

ビルド後のイメージは次のようになります。

.next/
├── standalone/
│   ├── server.js
│   ├── package.json
│   ├── .next/
│   └── node_modules/   // 本番実行に必要な一部だけ
└── static/

server.js はNext.jsが生成する最小限の起動ファイルです。通常の next start の代わりに、次のように起動できます。

node .next/standalone/server.js
bash

本番環境でポートやホストを指定したい場合は、環境変数を使います。

PORT=8080 HOSTNAME=0.0.0.0 node .next/standalone/server.js
bash

設定ファイルで意識すること

output: 'standalone'next.config.ts または next.config.js に書きます。この設定は ビルド時 に効くため、変更したら npm run build をやり直す必要があります。

// next.config.ts
import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  output: 'standalone',
};
 
export default nextConfig;
ts

standalone は必要なファイルを自動で追跡しますが、fs で読み込む設定ファイル、テンプレート、証明書、外部バイナリなどは追跡から漏れることがあります。その場合は、outputFileTracingIncludes で明示的に含めます。

// next.config.ts
import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  output: 'standalone',
  outputFileTracingIncludes: {
    '/*': ['src/config/runtime/**/*.json'],
  },
};
 
export default nextConfig;
ts

反対に、不要な大きいファイルが含まれてしまう場合は outputFileTracingExcludes で除外できます。Dockerイメージが大きくなりすぎる場合は、まず .next/standalone の中身を確認すると原因を追いやすいです。

また、public.next/static.next/standalone に自動コピーされません。CDNやリバースプロキシで配信するのが理想ですが、単体のNode.jsサーバーで配信したい場合は、ビルド後にコピーします。

cp -r public .next/standalone/
cp -r .next/static .next/standalone/.next/
bash

Dockerでは、ビルドステージで npm run build したあと、実行ステージに .next/standalone.next/staticpublic をコピーする構成がよく使われます。

COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
 
CMD ["node", "server.js"]
dockerfile

開発時との違い

開発中の npm run dev は、standalone の仕組みを使いません。開発サーバーはソースコードを監視し、変更を即時反映するために動いています。

一方、standalone は本番用に next build した後の成果物です。主な違いは次のとおりです。

項目開発時standalone本番
起動コマンドnpm run devnode server.js
入力ソースコード全体.next/standalone の成果物
変更反映ファイル保存で即時反映再ビルドと再デプロイが必要
目的開発・デバッグ小さい成果物で本番実行
node_modules開発依存も含めて存在実行に必要な一部だけをコピー

ローカルで本番に近い確認をしたい場合は、次の順で確認します。

npm run build
node .next/standalone/server.js
bash

この確認は npm run dev とは別物です。next.config.ts の本番向け設定、環境変数、静的ファイルのコピー漏れ、Docker上での起動パスなどは、standalone の成果物で確認しないと気づきにくいことがあります。

Node.jsサーバーやDockerは、Next.js機能の自由度が高い一方で、次の運用を自分で考える必要があります。

  • プロセス管理
  • ログ収集
  • ヘルスチェック
  • スケールアウト
  • CDN
  • 環境変数
  • DBコネクション
  • HTTPS / ドメイン

DockerビルドはコンテナでやるべきかCIでやるべきか

Next.jsのDockerイメージを作るとき、「コンテナ内で npm run build する(multi-stage build)」のか「CIで先にビルドして成果物だけコピーする」のか、迷うことがあります。

学習者学習者

CI側でビルドしてDockerにはCOPYだけ、のほうがシンプルに思えるけど、どっちが正解なの?

先生先生

どちらも動くけど、公式が推奨しているのはコンテナ内でビルドするmulti-stage buildだよ。Docker公式・Next.js公式ともにこの構成で案内している。理由は「誰がどこでビルドしても同じ結果になる」再現性の高さだね。

観点コンテナ内ビルド(multi-stage)CIでビルド → COPYのみ
公式推奨Yes(Docker公式・Next.js公式ともに)No(公式ドキュメントに記載なし)
再現性高い — 環境差異がないCIとDockerの環境差で壊れうる
ビルド速度Dockerレイヤキャッシュに依存CIキャッシュが効きやすく速い場合がある
Dockerfilemulti-stage(deps → build → runner の3段階)単純な COPY のみ
デバッグDockerfileの中で完結するCI設定とDockerfileの両方を見る必要がある

multi-stage buildの構成例

Next.js公式の Docker Example で紹介されている構成は、大まかに次の3段階です。

# 1. deps — 依存だけインストール
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
 
# 2. builder — ソースをコピーしてビルド
FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
 
# 3. runner — 実行に必要なファイルだけ持ってくる
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
 
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
 
CMD ["node", "server.js"]
dockerfile
学習者学習者

3段階に分ける理由は何?全部1つのステージでやったらダメなの?

先生先生

最終イメージに開発用の node_modules やソースコードが残らないようにするためだよ。runnerステージにはビルド済みの成果物しか入らないから、イメージサイズが小さくなるし、本番に不要なファイルが漏れるリスクも減る。


static exportで静的サイトとして配信する場合

完全な静的サイトでよければ、output: 'export' を使ってHTML/CSS/JSだけを書き出せます。

// next.config.ts
import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  output: 'export',
};
 
export default nextConfig;
ts

この場合、S3、Nginx、Apache、GitHub Pagesのような静的ホスティングでも配信できます。

ただし、static exportではサーバーが必要な機能は使えません。

使える / 使いやすい使えない / 制限されやすい
静的なページSSR
静的生成されたブログRoute Handlers
クライアント側だけで完結する画面Server Actions
外部APIをブラウザから直接呼ぶ構成Proxy
画像を事前に最適化する構成動的な画像最適化

Route HandlersServer Actions を使うアプリは、基本的にstatic exportではなく、サーバー機能を持つデプロイ先を選びます。


Cloudflare Workersにデプロイする場合

Cloudflare Workersは、Node.jsサーバーではなく workerd というWorkers Runtimeで動きます。そのため、Next.jsアプリをそのまま next start で動かすのではなく、Cloudflare向けに変換する工程が必要です。

Cloudflare公式では、Next.jsアプリをWorkersへデプロイする方法として OpenNext adapter を使う流れが案内されています。

新規プロジェクトなら、CloudflareのCLIからNext.js向けに作成できます。

npm create cloudflare@latest -- my-next-app --framework=next
bash

既存プロジェクトなら、現在のCloudflareドキュメントでは wrangler deploy による自動検出、または手動設定が案内されています。

npx wrangler deploy
bash

手動で構成する場合は、概ね次のような工程になります。

  1. @opennextjs/cloudflare を入れる
  2. wrangler を入れる
  3. wrangler.jsonc または wrangler.toml を作る
  4. compatibility_flagsnodejs_compat を設定する
  5. open-next.config.ts を作る
  6. preview / deploy スクリプトを追加する
  7. npm run preview でWorkers Runtimeに近い環境で確認する
  8. npm run deploy で公開する
{
  "scripts": {
    "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
    "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy"
  }
}
json

Cloudflare OpenNext adapterは多くのNext.js機能をサポートしていますが、Node.jsランタイム前提の機能や一部の新機能は対応状況を確認する必要があります。たとえばCloudflare公式ドキュメントでは、Node.js in Middlewareは「not yet supported」とされています。これは ProxyとMiddleware で触れたランタイム差分とつながる話です。

詳細はCloudflare公式の Next.js on Cloudflare Workers と、OpenNextの Cloudflare adapter documentation を確認してください。


エッジ環境へ出すときの注意点

Cloudflare Workers、Vercel Edge、Deno Deployのようなエッジ寄りの環境は、ユーザーに近い場所で軽く処理できるのが強みです。一方で、Node.jsサーバーとは前提が違います。

観点Node.jsサーバーエッジ環境
実行環境Node.jsWeb標準API中心のランタイム
ファイル操作fs が使える使えないことが多い
npmパッケージNode.js前提でも動きやすいEdge対応が必要
DB接続TCP接続しやすいHTTPベースや専用接続が向きやすい
確認方法next start に近いadapterのpreviewで確認する

ProxyとMiddleware でも説明した通り、エッジ環境は「Node.jsをそのまま小さくしたもの」ではありません。fs、ネイティブモジュール、Node.js専用APIに依存するライブラリは、本番で動かない可能性があります。

学習者学習者

ローカルでは動いたのにCloudflareに出したら落ちる、というのはランタイム差分が原因になりやすいんだね。

先生先生

そう。だからCloudflare Workersへ出すなら、npm run preview のように本番ランタイムに近い確認を必ず挟む。Vercel以外では特に大事だよ。


環境変数と本番ビルドの注意点

Next.jsでは、環境変数が「ビルド時に必要なもの」と「実行時に必要なもの」に分かれます。

種類注意点
ビルド時に必要SSGで使うAPIキー、NEXT_PUBLIC_...ビルド環境に設定する
実行時に必要DB URL、外部APIの秘密鍵Runtime側に設定する
ブラウザに出るNEXT_PUBLIC_ANALYTICS_ID秘密情報を入れない
サーバーだけDATABASE_URLクライアントコードへ渡さない

特にCloudflare Workers BuildsやCI/CDでは、ビルド時に必要な環境変数が設定されていないと、静的生成やビルド内のデータ取得で失敗します。VercelでもCloudflareでも、Production / Preview / Developmentで値を分けることを意識しましょう。


デプロイ前チェックリスト

本番公開前に、最低限ここを確認しましょう。

チェック項目見るポイント
npm run build が通る型・Lint・静的生成エラーを確認
環境変数が設定されているProduction / Previewで不足がないか
DB接続先が本番向けローカルDBやテストDBを参照していないか
認証・認可がサーバー側にあるServer Actions / Route Handlers で確認
robots.txt / sitemap.xmlSEO公開範囲が意図通りか
OGP / metadataメタデータとSEO の設定が本番URLになっているか
エラー監視Sentryなどで本番エラーを拾えるか
ログAPIエラーや認証エラーを追えるか
ロールバック手段失敗時に戻せるか

まとめ

  • Next.jsはVercel専用ではなく、Node.jsサーバー、Docker、static export、Adapter経由の各プラットフォームへデプロイできる
  • VercelはNext.js向けのゼロ設定デプロイ、Preview Deployment、Vercel Functions、画像最適化、キャッシュ統合などが強い
  • Vercel固有の運用機能は便利だが、他プラットフォームではCI/CD、CDN、画像最適化、ログ監視などを別途組み合わせる
  • static exportは静的配信に向くが、Route Handlers、Server Actions、SSR、Proxyなどサーバー機能は使えない
  • Cloudflare Workersへ出す場合はOpenNext adapterやWranglerを使い、workerd ランタイムでpreviewする
  • エッジ環境はNode.jsと同じではないため、Node.js API依存・DB接続・Middleware/Proxyの対応状況に注意する
  • 本番前には npm run build、環境変数、認証・認可、SEO、ログ、ロールバックを確認する

これでNext.js App Routerの基礎から、API、Proxy、Server Actions、デプロイまで一通りつながりました。実際のアプリでは、ここから認証、DB設計、テスト、監視を少しずつ足していくと、本番運用できる形に近づきます。

Next.jsクイズに挑戦するこの章で学んだNext.jsの知識を、4択クイズでアウトプットして定着させよう