# Vercel 移行ガイド：自前ホスト（AWS/EC2/Netlify）から無停止で乗り換える実践手順

> Next.jsアプリを自前ホスト（AWS EC2/ECS/Amplify）やNetlifyからVercelへ無停止で移行する実践ガイド。移行可否の見極め、環境変数とシークレットの移送、ステートフル依存（DB/ファイル/cron）の置き換え、プレビューでの並走検証、DNSカットオーバーとロールバック、移行後のコスト最適化までを公式準拠の手順で解説します。

- 公開日: 2026-06-28
- 著者: 友田 陽大
- タグ: Vercel, Next.js, インフラ, アーキテクチャ設計, CI/CD, コスト最適化, DX
- URL: https://tomodahinata.com/blog/vercel-migration-aws-self-hosted-to-vercel-guide
- カテゴリ: Vercel 本番運用
- 総合ガイド: https://tomodahinata.com/blog/vercel-production-platform-guide

## 要点

- 移行の鍵は『一気に切り替えない』こと。Vercelのプレビューデプロイで本番と並走検証し、DNSのカットオーバーは最後の一手にする。問題があればDNSを戻すだけで即ロールバックできる構成にする
- 移行可否の見極めが最初の関門。ステートレス・標準Next.jsなら容易。ローカルファイル書き込み・常駐プロセス・WebSocketサーバー・VPC内専用DBなど『サーバー前提』の依存は、Blob/外部DB/Workflows/Marketplaceへ置き換える設計が必要
- 環境変数はvercel env addで3環境（production/preview/development）に整理して移送。NEXT_PUBLIC_に機密を載せない。外部クラウドへは長命キーを置かずOIDC鍵レスへ。秘密はコードに残さない
- DB接続はサーバーレスで枯渇しやすいため、pooled接続（Neon等）へ。ローカルファイルはVercel Blob、定期実行はCron Jobs、長時間処理はWorkflows/キューへ。状態の置き場所を用途で再設計する
- カットオーバーはTTLを事前に短縮→プレビュー検証→本番Promote→DNS切替→x-vercel-cacheとログで監視。移行後はキャッシュ設計とActive CPU課金前提でコストを最適化する

---

「Next.js を EC2 や ECS、あるいは Netlify で動かしているが、運用の手間とデプロイの遅さに疲れた。Vercel に移したい。でも止めたくない」——この相談は本当に多いです。移行は**やり方さえ間違えなければ無停止**で、しかもロールバックも一瞬です。逆に、ステートフルな依存を見落とすと本番で詰まります。

この記事は、自前ホスト（AWS/EC2/ECS/Amplify）や Netlify から Vercel へ**無停止で移行する実践手順**を、[Vercel 公式ドキュメント](https://vercel.com/docs)に忠実にまとめます。移行先の本番運用の全体像は [Vercel 本番運用ガイド](/blog/vercel-production-platform-guide) を参照してください。

---

## 移行の大原則：DNS カットオーバーを最後にする

移行で最も多い事故は「いきなり本番ドメインを Vercel に向けて、動かない」。これを避ける鉄則は——

```
①Vercelにデプロイ（プレビューURLで動く状態を作る）
   ↓
②プレビューで本番同等の検証（並走）
   ↓
③本番ブランチへPromote（まだ独自ドメインは旧基盤）
   ↓
④DNSを切り替える（最後の一手）
   ↓
⑤問題があればDNSを戻すだけ＝即ロールバック
```

DNS を**最後の一手**にすることで、切り替え前にいくらでも検証でき、問題時は DNS を戻すだけで旧基盤に復帰できます。

---

## ステップ0：移行可否を見極める（最重要）

コードを動かす前に、**「サーバー前提の依存」を棚卸し**します。ここを飛ばすと本番で詰まります。Vercel はステートレスなサーバーレス基盤なので、以下は置き換えが必要です。

| 旧基盤での依存 | Vercel での置き換え |
|---|---|
| **ローカルファイル書き込み**（アップロード保存・生成PDF） | [Vercel Blob](/blog/vercel-storage-blob-edge-config-marketplace-guide)（client upload） |
| **常駐プロセス / バックグラウンドワーカー** | [Cron Jobs](/blog/vercel-functions-fluid-compute-streaming-cron-guide) / Queues / Workflows |
| **長時間処理**（バッチ・動画変換、>数分） | Vercel Workflows（実行時間無制限）/ 外部ジョブ |
| **WebSocket サーバー常駐** | SSE / 外部リアルタイム基盤（Ably/Pusher等）/ 別途常駐基盤 |
| **VPC 内専用 DB（公開エンドポイントなし）** | 公開＋認証付きエンドポイント化、または Marketplace(Neon等)、Secure Compute(Ent) |
| **インメモリのセッション/レート制限** | Redis(Upstash) / Edge Config / 外部ストア |
| **巨大なモノリス（>250MB バンドル）** | 機能分割、または対象は別基盤に残す |

> **判断**：標準的な Next.js（App Router、ステートレス、外部 DB）なら移行は**容易**。逆に「ファイルをローカルに書く」「常駐プロセスに依存」が深いほど、移行は**再設計**を伴います。ここを正直に評価するのが成否を分けます。

---

## ステップ1：プロジェクトを Vercel に接続

Git 連携が最短です。リポジトリをインポートすると、プッシュごとにプレビューが作られます。

```bash
npm i -g vercel@latest
vercel login
vercel link            # 既存プロジェクトに紐付け（or 新規作成）
vercel                 # プレビューデプロイを作成 → 固有URLで動作確認
```

フレームワークは自動検出されますが、**ビルドコマンド・出力ディレクトリ・ルートディレクトリ**（モノレポなら特に）を設定で確認します。モノレポは [Turborepo](/blog/pnpm-turborepo-monorepo-architecture-type-coverage-guide) のルート設定に注意。

---

## ステップ2：環境変数とシークレットを移送

旧基盤の環境変数を、Vercel の**3環境（production / preview / development）**へ整理して移します。

```bash
# 本番のシークレットを production だけに登録
vercel env add DATABASE_URL production
vercel env add STRIPE_SECRET_KEY production

# プレビューには本番と別の値（ステージングDB等）を
vercel env add DATABASE_URL preview

# ローカル開発用をローカルへ同期
vercel env pull .env.local
```

移送時の必須チェック（[環境変数ガイド](/blog/vercel-environment-variables-secrets-oidc-management-guide)）：

- **`NEXT_PUBLIC_` 接頭辞に機密を載せない**（ブラウザに露出）。API キーは無印で。
- 環境変数の変更は**新しいデプロイにのみ適用**される（既存デプロイは変わらない）。
- 外部クラウド（AWS S3/SES 等）へは、長命のアクセスキーを置かず **OIDC 鍵レス**へ切り替える好機。
- 合計サイズは**デプロイあたり 64KB**まで。

---

## ステップ3：ステートフル依存を置き換える

### ローカルファイル → Vercel Blob

EC2 のディスクに保存していたアップロードファイルや生成 PDF は、Blob へ。ユーザーアップロードは **client upload**（サーバーを経由せず、転送課金と 4.5MB 制限を回避）。

```ts
// 旧：fs.writeFileSync(path, buffer)
// 新：Vercel Blob（private で保存し、関数経由で配信）
import { put } from "@vercel/blob";
const blob = await put(`uploads/${id}.pdf`, buffer, {
  access: "private",
  addRandomSuffix: true,
});
```

### DB 接続 → pooled 接続で枯渇を防ぐ

サーバーレスの並行性下では「1接続＝1プロセス」の Postgres が枯渇します。**pooled 接続**（Neon の pooled エンドポイント等）へ。

```ts
// Neon の pooled 接続（サーバーレスでは必須級）
import { neon } from "@neondatabase/serverless";
const sql = neon(process.env.DATABASE_URL!); // pooled エンドポイント
```

接続枯渇の理屈は [PgBouncer・接続プーリング](/blog/postgresql-connection-pooling-pgbouncer-serverless-guide) を参照。VPC 内の専用 DB は、公開＋認証エンドポイント化するか、Enterprise の Secure Compute を検討します。

### cron / 常駐ワーカー → Cron Jobs / Workflows

```json
// 旧：crontab や常駐デーモン → vercel.json の crons
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "crons": [{ "path": "/api/cron/nightly", "schedule": "0 0 * * *" }]
}
```

Cron は `CRON_SECRET` で必ず保護し、長時間処理は Workflows/キューへ（[Functions ガイド](/blog/vercel-functions-fluid-compute-streaming-cron-guide)）。

---

## ステップ4：プレビューで並走検証

DNS を切る前に、プレビュー（または Vercel の `*.vercel.app` 本番URL）で**本番同等の検証**を行います。

- **E2E（Playwright）**をプレビューURLに対して実行（[E2E 設計](/blog/playwright-e2e-testing-production-design-guide)）。
- 主要導線（ログイン・決済・アップロード・検索）を手動確認。
- `x-vercel-cache` でキャッシュが意図通り `HIT`/`PRERENDER` か確認（[キャッシュ](/blog/vercel-caching-isr-cache-components-ppr-guide)）。
- 必要なら**旧基盤と Vercel を一定期間並走**させ、トラフィックの一部だけ Vercel に流して比較（DNS の加重や、フロントのフラグで段階移行）。

---

## ステップ5：DNS カットオーバーとロールバック

いよいよ本番ドメインを切り替えます。

```
事前：DNSレコードのTTLを短く（例 300秒）しておく（切替・巻き戻しを速く）
  ↓
Vercelにカスタムドメインを追加し、指示どおりA/CNAMEレコードを設定
  ↓
本番デプロイをPromote（Rolling Releases併用なら段階配信）
  ↓
DNSを切り替え → 伝播を監視（dig / 監視ツール）
  ↓
問題があれば：DNSを旧基盤に戻す（即ロールバック）
            or Vercel側はInstant Rollbackで前デプロイへ
```

- TTL を事前に短縮しておくと、切替も巻き戻しも速い。
- Vercel 側の不具合は **Instant Rollback** で即前デプロイへ。基盤ごと戻すなら DNS を戻す。
- Rolling Releases ＋ Skew Protection を使えば、本番でも段階的に Vercel デプロイを広げられる（[デプロイ](/blog/vercel-deployments-cicd-rollback-rolling-releases-guide)）。

---

## ステップ6：移行後の最適化

移行は「動いた」がゴールではありません。

- **キャッシュ設計**：旧基盤で SSR だったページを ISR/CDN キャッシュへ。`x-vercel-cache` で `HIT` を実測（[キャッシュ](/blog/vercel-caching-isr-cache-components-ppr-guide)）。
- **コスト**：Active CPU 課金前提で、重い CPU 処理を分離、メモリ/`maxDuration` を用途に合わせる（[コスト](/blog/vercel-cost-active-cpu-pricing-optimization-guide)）。
- **セキュリティ**：WAF/BotID で入口を守り、OIDC 鍵レスへ移行（[Firewall](/blog/vercel-firewall-waf-botid-ddos-security-guide)）。
- **可観測性**：Observability で関数・エラー率・CWV を監視（[可観測性](/blog/vercel-observability-monitoring-speed-insights-log-drains-guide)）。

---

## 移行チェックリスト

- [ ] **サーバー前提の依存**（ファイル/常駐/長時間/VPC内DB）を棚卸し・置き換え設計
- [ ] 環境変数を3環境に整理、`NEXT_PUBLIC_` に機密なし、変更は新デプロイのみ反映を理解
- [ ] DB は **pooled 接続**、ローカルファイルは **Blob**、cron は **Cron Jobs**
- [ ] プレビューで **E2E・主要導線・`x-vercel-cache`** を検証
- [ ] DNS の **TTL を事前短縮**、カスタムドメイン設定
- [ ] カットオーバー後の**監視**と、DNS/Instant Rollback の**戻し手順**を用意
- [ ] 移行後に**キャッシュ・コスト・セキュリティ・可観測性**を最適化

---

## まとめ

Vercel への移行は、**「DNS を最後に切る」「ステートフル依存を先に置き換える」**の2点を守れば、無停止で安全に進められます。

1. **可否を正直に見極める**（サーバー前提の依存が鍵）
2. プレビューで**並走検証**してから DNS を切る
3. ファイル→Blob、DB→pooled、cron→Cron Jobs、長時間→Workflows
4. **TTL 短縮 → Promote → DNS 切替 → 監視 → 戻せる**構成
5. 移行後に**キャッシュ・コスト・セキュリティ・可観測性**を仕上げる

移行可否の見極めから、ステートフル依存の再設計、無停止カットオーバー、移行後のコスト最適化まで、案件として伴走します。

> 本記事は [Vercel 公式ドキュメント](https://vercel.com/docs)（環境変数・Blob・Cron・ドメイン、2026年6月時点）に基づきます。仕様は更新されるため、本番採用時は公式で最新値を確認してください。
