#16までで、機能・品質・パフォーマンスの整ったミニブログが完成しました。
しかし、これを実際に運用していく上で、まだ大事な仕組みが1つ欠けています。
「テストが通ったコードだけを、安全に本番へ届ける仕組み」です。
今回は、Vercelのプレビュー環境を活用したステージング運用と、#15で書いたテストをGitHub Actionsで自動実行してからデプロイするCI/CDパイプラインを構築します。
この記事は#15のテストと#8のVercelへのデプロイの知識が前提です。
この記事のゴール
- ブランチ戦略と、Vercelのプレビュー環境の仕組みを理解する
- 環境ごと(開発/プレビュー/本番)に環境変数を使い分ける
- GitHub Actionsで、テストが通ったコードだけをmainブランチにマージできるようにする
なぜ環境を分ける必要があるのか
個人開発の初期段階では、「mainブランチにpushしたら即本番反映」で問題ありません。
しかし、次のような状況になると、本番環境に直接pushするのは危険になってきます。
- 新機能を試したいが、既存ユーザーには見せたくない
- チームで開発しており、他の人の変更と自分の変更が衝突していないか確認したい
- リリース前に、実際の本番相当の環境で最終確認をしたい
これらを解決するのが、開発環境・プレビュー(ステージング)環境・本番環境という3段階の構成です。
| 環境 | 役割 | URL例 |
|---|---|---|
| 開発(Development) | 手元のPCで動かす | localhost:3000 |
| プレビュー(Preview) | プルリクエストごとに自動生成される、確認用の環境 | my-blog-git-feature-x.vercel.app |
| 本番(Production) | 実際のユーザーがアクセスする環境 | my-blog.vercel.app |
Vercelのプレビュー環境を理解する
Vercelは、GitHubリポジトリと連携している場合、プルリクエストを作成するたびに自動でプレビュー環境をデプロイしてくれます。
追加の設定はほとんど必要ありません。
feature/add-commentのようなブランチを作成し、変更をpush- GitHub上でプルリクエストを作成
- Vercelが自動的にビルド・デプロイを実行し、プルリクエストのコメント欄にプレビューURLが表示される
このプレビューURLは、本番とは完全に独立した環境です。
ここで自由に動作確認を行い、問題なければmainブランチにマージする、という流れになります。
① ローカル開発(Development環境)
コードを書く
│
▼
② プルリクエスト作成
featureブランチをpush
│
├──────────────┬──────────────┐
▼ ▼
③ Vercel Preview環境 ④ GitHub Actions
自動でデプロイ テストを自動実行
│ │
└──────────────┬──────────────┘
▼
⑤ レビュー完了 + CIが緑(両方そろって初めて)
mainへマージ
│
▼
⑥ Vercel Production環境
本番へ自動デプロイ環境ごとに環境変数を使い分ける
#9〜#14で扱ってきたDATABASE_URLやAUTH_GOOGLE_IDなどの環境変数は、本番用とプレビュー用で値を分けるのが望ましいです。
特にデータベースは、プレビュー環境が誤って本番のデータを書き換えてしまう事故を防ぐため、必ず別インスタンスを用意します。
Vercel
Vercelのダッシュボードでは、環境変数ごとに適用範囲を指定できます。
Settings→Environment Variablesを開く- 変数を追加する際、
Production/Preview/Developmentのチェックボックスで適用範囲を選択
DATABASE_URL
Production: postgresql://...本番用Supabaseプロジェクト
Preview: postgresql://...ステージング用Supabaseプロジェクト
Development: postgresql://...ローカル用(.envファイルで管理)Supabase側でも、本番用とステージング用でプロジェクトを分けて作成しておきます。
無料プランの範囲内でも複数プロジェクトを作成できるため、コストをかけずに環境を分離できます。
Google OAuthの「承認済みのリダイレクトURI」(#10参照)にも、それぞれの環境のURLを追加しておく必要があります。
http://localhost:3000/api/auth/callback/google
https://my-blog.vercel.app/api/auth/callback/google
https://my-blog-git-*.vercel.app/api/auth/callback/google # プレビュー環境用(ワイルドカード非対応の場合は個別追加)Googleの設定はワイルドカードに対応していない場合があります。
その場合は、ステージング専用の固定ブランチ(例:
staging)を1つ用意し、そのブランチのプレビューURLだけを登録する運用にすると管理しやすくなります。GitHub Actionsとは何か
ここから使うGitHub Actionsについて、先に説明しておきます。
GitHub Actionsは、GitHubに標準で組み込まれている自動化の仕組みです。
「プルリクエストが作られたら」「mainにpushされたら」といったGitHub上の出来事(イベント)をきっかけに、あらかじめ決めておいた処理(テストの実行やビルドなど)を自動で走らせることができます。
この記事で作るのは、「プルリクエストが作られたら、自動でテストを実行する」という仕組みです。
テストが通らなければ、そのプルリクエストはmainにマージできないようにする、というところまで含めて構築します。
全体の構成要素
GitHub Actionsは、いくつかの言葉を組み合わせて理解すると分かりやすくなります。
用語 意味 ワークフロー(workflow) 「何をきっかけに、何を実行するか」をまとめたファイル1つ全体のこと。 .github/workflows/フォルダの中にYAMLファイルとして置くトリガー( on)ワークフローを起動するきっかけ。「プルリクエストが作られたとき」「mainにpushされたとき」など ジョブ( jobs)ワークフローの中の作業のまとまり。「テストを実行するジョブ」のように、目的ごとに分ける ステップ( steps)ジョブの中の、1つ1つの具体的な処理。「依存関係をインストールする」「テストを実行する」など、上から順番に実行される 実行環境( runs-on)そのジョブをどんなマシン(OS)の上で動かすか。 ubuntu-latestと書けば、GitHubが用意した使い捨てのLinux環境が使われるこれから作るワークフローファイルは、「プルリクエストが作られたとき(トリガー)」に、「テストという名前のジョブ(jobs)」が「Ubuntu環境(runs-on)」の上で、「依存関係のインストール→マイグレーション→テスト→ビルド、という一連のステップ(steps)」を順番に実行する、という中身になっています。
GitHub Actionsでテストを自動実行する
プレビュー環境は「デプロイはされるが、テストが通っているとは限らない」状態です。
ここに、#15で書いたテストを組み込み、テストが失敗しているコードはマージできないようにします。
ワークフローファイルを作成する
プロジェクトのルートに.github/workflows/というフォルダを作り、その中にci.ymlというファイルを作成します。
mkdir -p .github/workflows# .github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: test_db
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: 依存関係をインストール
run: npm ci
- name: Prismaマイグレーションを実行
run: npx prisma migrate deploy
env:
DATABASE_URL: postgresql://test:test@localhost:5432/test_db
- name: ユニットテストを実行
run: npm run test
env:
DATABASE_URL: postgresql://test:test@localhost:5432/test_db
- name: ビルド
run: npm run build
env:
DATABASE_URL: postgresql://test:test@localhost:5432/test_db
AUTH_SECRET: test-secret
AUTH_GOOGLE_ID: dummy
AUTH_GOOGLE_SECRET: dummy
- name: Playwrightブラウザをインストール
run: npx playwright install --with-deps chromium
- name: E2Eテストを実行
run: npx playwright test
env:
DATABASE_URL: postgresql://test:test@localhost:5432/test_db
PLAYWRIGHT_TEST: "true"先ほどの用語と照らし合わせると、on.pull_requestがトリガー、jobs.testがジョブ、その下の- uses: ...や- name: ...が並んでいる部分がステップにあたります。
いくつか補足しておきます。
servicesで、本物のPostgreSQLコンテナをCI上に立てています。#15でPrismaをモック化したユニットテストとは別に、Playwrightで実行するE2Eテストは実際のDBに対して動作確認を行うため、CI環境にも使い捨てのDBが必要ですBETTER_AUTH_SECRET/GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRETはビルドを通すためのダミー値です。CIのテストでは実際のGoogleログインは行わず(#15のテスト用メール/パスワード認証を使う)、これらの値が本物である必要はありませんenv:は、そのステップだけで使える環境変数を指定しています。CI環境には.envファイルが存在しないため、ここで明示的に渡す必要があります
重要:
このci.ymlは、前のセクションで設定した「Production/Preview/Developmentごとの環境変数」とは無関係に動きます。
GitHub ActionsのCIは、実際にアプリをデプロイしているわけではなく、「コードが正しく動くか」だけを使い捨ての環境で検証するものなので、常に同じダミー値で十分です。
Production/Previewの環境変数を実際に使い分けているのは、Vercel側のデプロイだけです。
プルリクエストを作ると、VercelのデプロイとGitHub ActionsのCIはそれぞれ独立して並行に動き、お互いの設定を参照し合うことはありません。
ワークフローファイルを配置する
作成したci.ymlは、他のコードと同じようにGitへコミットし、pushします。
git add .github/workflows/ci.yml
git commit -m "Add CI workflow"
git pushこのファイルがmainブランチに存在していれば、今後プルリクエストを作成するたびに自動でこのワークフローが実行されます。
試しに適当なブランチを作ってプルリクエストを開き、GitHubの「Actions」タブ(リポジトリ上部のタブの1つ)を確認してみてください。
ワークフローが実行され、進行状況がリアルタイムで表示されるはずです。
mainブランチをブランチ保護する
GitHubリポジトリのSettings → Branchesで、mainブランチに対して以下を設定します。
- 「Require status checks to pass before merging」を有効化し、先ほどのCIワークフロー(
testジョブ)を必須項目として指定 - 「Require a pull request before merging」を有効化
これにより、CIのテストが通らない限り、mainブランチにマージできなくなります。
誤ってバグを含んだコードが本番にデプロイされる事故を、仕組みとして防げます。
リリースの流れ全体を確認する
ここまでの設定で、以下のような開発フローが完成します。
feature/xxxブランチで機能を開発する- プルリクエストを作成する
- Vercelが自動でプレビュー環境をデプロイ → 目視で確認できる
- GitHub Actionsがテストを自動実行 → ロジックレベルで壊れていないか確認できる
- レビューが完了し、CIが緑(成功)になったら
mainにマージする mainへのマージをトリガーに、Vercelが本番環境へ自動デプロイする
「人間の目でのレビュー」と「機械によるテスト」の両方を通過したコードだけが本番に届く、という二重のチェック体制になっています。
デプロイ後に問題が起きた場合
万が一、本番デプロイ後に問題が発覚した場合は、Vercelのダッシュボードから即座に1つ前のデプロイにロールバックできます。
Deploymentsタブを開く- 問題が起きる前の、正常だったデプロイを選択
- 「Promote to Production」を選択
新しく修正コードをpushしてビルドし直すよりも、ロールバックの方が圧倒的に早く復旧できます。
まず切り戻して被害を止め、原因調査はその後で落ち着いて行う、という判断ができるようにしておくと安心です。
まとめ
この記事では、以下を実装しました。
- Vercelのプレビュー環境を使い、プルリクエストごとに確認用の環境を自動生成
- 本番・プレビュー・開発で環境変数(特にDATABASE_URL)を分離
- GitHub Actionsで、ユニットテスト・E2Eテスト・ビルドを自動実行するCIパイプラインを構築
- ブランチ保護により、テストが通らないコードは本番にマージできない仕組みを整備
これで、安心して機能追加を続けられる開発基盤が整いました。
いよいよ次回、最終回の#18 ミニブログを完成させる — シリーズ総仕上げでは、実践編で学んだすべての要素を振り返りながら、詰まりやすいポイントのFAQと、この先の学習ロードマップをまとめます。


























