http://localhost:3000でアプリが動いた。自分のブラウザでは、画面もAPIも問題なく使える。そこでURLを友人へ送ってみても、相手の画面には何も表示されません。

localhostは「このパソコン自身」という意味です。自分のパソコンで起動したアプリは、通常、そのパソコンの中からしか開けません。開発サーバーを止めれば動かなくなりますし、パソコンを閉じても止まります。

アプリを自分のパソコンの外へ置き、ほかの人が公開URLから使える状態にする作業がデプロイです。

コーディングエージェントに「デプロイして」と頼めば、設定ファイルや自動化のコードまで作ってくれます。ただし、画面にDeploy successfulと表示されたことと、利用者が安全に使えることは同じではありません。この記事では、エージェントが作ったデプロイ設定を見たときに、何がどこへ公開され、どこを確認すべきかが分かるところまでを扱います。

デプロイすると何が変わるのか

ローカルで開発している間、アプリを動かしているのは自分のパソコンです。デプロイ後は、Vercel、Cloudflare、AWSなどが管理する環境でアプリが動きます。

大まかな流れは次のとおりです。

  1. コードをGitHubへ送る
  2. 必要なパッケージを入れる
  3. テストする
  4. 本番用にビルドする
  5. デプロイ先へ配置する
  6. 公開URLから確認する

デプロイ先によっては、GitHubのリポジトリを接続するだけで、この流れを自動的に実行してくれます。GitHub Actionsを使い、自分で手順を決めることもできます。

npm run devnpm run build

Next.jsでは、開発中にnpm run devを使うことがよくあります。これは、ファイルを変更したら画面へすぐ反映するなど、開発しやすさを優先した動かし方です。

デプロイ前には、通常npm run buildで本番用の成果物を作ります。開発中には気づかなかった型の不一致、存在しない環境変数、サーバーでしか使えない処理などが、この段階でエラーになることがあります。

「自分のパソコンでは動いたのに、デプロイできない」ときは、まずビルドが成功しているかを確認します。

自分のパソコンとの違い

デプロイ先では、次のような違いがあります。

  • Node.jsのバージョンが違う
  • Linux上で動くため、ファイル名の大文字と小文字が区別される
  • .env.localの内容が自動的には渡らない
  • 書き込んだファイルが、次の実行やデプロイまで残るとは限らない
  • 一回の処理時間やメモリに上限がある
  • 一定時間使われない処理が停止し、次のアクセス時に起動することがある

エージェントへデプロイを頼むときは、コードだけでなく、実行環境の違いも確認してもらいます。

「消えずに残る」を分けて考える

公開URLができると、アプリ全体がずっと同じ状態で残るように感じます。しかし、残したいものによって保存先は違います。

アプリを動かし続ける

デプロイ後は、自分のパソコンを閉じても公開URLへアクセスできます。ただし、同じプログラムが一台のコンピューターで永遠に動き続けるとは限りません。サーバーレス環境では、必要なときに処理が起動し、終わると停止することがあります。

会員情報や投稿を残す

会員情報、記事、注文、チャット履歴などは、D1やPostgreSQLといったデータベースへ保存します。プログラムが再起動しても、データベースへ保存した情報は残ります。

画像や動画を残す

利用者がアップロードした画像を、プログラムが動く一時的なフォルダーへ保存してはいけません。Cloudflare R2、Amazon S3、Vercel Blobなど、ファイルを残すためのストレージを使います。

コードを残す

コードはGitHubで履歴を管理します。デプロイ先にもバージョン履歴が残ることがありますが、GitHubの代わりではありません。

  • コード: GitHub
  • 実行するアプリ: Vercel / Cloudflare / AWS
  • 会員情報や投稿: データベース
  • 画像やアップロード物: オブジェクトストレージ
  • APIキー: Secrets

デプロイ先を決めるときは、「アプリをどこで動かすか」だけでなく、「データとファイルをどこへ残すか」も決めます。

友人のブラウザからLLMまでを追う

既存の要約アプリを例にします。利用者が文章を入力し、LLMが要約を返すアプリです。

安全な構成では、通信が次のように進みます。

  1. 友人のブラウザ
  2. 公開されたNext.jsの画面
  3. /api/summarize
  4. LLMのAPI

LLMのAPIキーは、ブラウザではなく/api/summarizeを動かす側に置きます。

利用者が調べられるブラウザと、利用者へ配られないバックエンドの信頼境界を分け、APIキーをシークレットからLLM APIへ渡す図

反対に、友人のブラウザからAPIキー付きでLLMのAPIへ直接通信する構成は避けます。

ブラウザへ届いたJavaScriptや通信内容は、利用者が確認できます。環境変数から読み込んだ値であっても、最終的にブラウザ用のコードへ埋め込めば秘密ではありません。

Next.jsでは、NEXT_PUBLIC_で始まる環境変数はブラウザ側から使うことを想定しています。APIキーやデータベース接続情報に、この名前を付けてはいけません。

アプリをどのように動かすか

デプロイ先を比べる前に、プログラムの動かし方を大まかに知っておきましょう。

常に動くサーバー

Amazon EC2などの仮想サーバーでは、一台のコンピューターを借りる感覚でプログラムを動かします。OSや実行中のプロセスを細かく管理できますが、更新、監視、セキュリティ設定など、自分で考える範囲も広くなります。

必要なときに動く関数

AWS LambdaやVercel Functionsなどでは、リクエストが届いたときに処理が動きます。ボタンを押したら短いAPI処理を行う、といったアプリに向いています。使われていない間もサーバーを動かし続ける必要がありません。

世界各地で動く処理

Cloudflare Workersなどは、利用者に近い場所で処理を実行できます。これをエッジと呼びます。ただし、「エッジ」はプログラムがいつ動くかではなく、主にどこで動くかを表す言葉です。

バックエンドを常駐またはリクエスト時のどちらで動かすかと、特定地域または分散したエッジのどこで動かすかを別々に選ぶ図

特殊なOS設定、長時間の処理、常時接続などが必要なら、一般的なサーバーレス関数では合わないことがあります。短いWeb APIなら、最初から仮想サーバーを管理しなくても作れる場合が多いです。

Vercel、Cloudflare、AWSを比べる

三つともWebアプリを公開できますが、同じサービスではありません。料金だけでなく、何を簡単にしてくれるかで比べます。

選択肢 始めやすい用途 良いところ 確認するところ
Vercel Next.js、個人のWebアプリ GitHub接続とプレビューが簡単 商用利用のプラン、利用上限、従量課金
Cloudflare Workers、Pages、D1を使うアプリ アプリ、DB、ファイル保存をまとめやすい Node.js互換性、各サービスの上限
AWS 細かな構成、大規模化、企業向け要件 選択肢と設定の自由度が高い 権限、ネットワーク、料金、サービス選定

Next.jsを最短で公開するならVercel

VercelはNext.jsを開発している会社のサービスです。GitHubのリポジトリを接続すると、pushやPull Requestに合わせてビルドとデプロイを行い、確認用のURLも作れます。

Hobbyプランは無料ですが、個人・非商用利用向けです。仕事や事業で使うアプリは、Pro以上を検討します。「無料で公開できたから、そのまま商用サービスにも使える」とは限りません。

小さな構成を低価格で運用するならCloudflare

CloudflareにはWorkersの無料枠があります。Paidプランもアカウント単位で最低月額5ドルから始まります。Workers、D1、R2などを同じ基盤で扱えるため、このシリーズで説明してきたデータベースやファイル保存ともつなげやすい構成です。

一方で、一般的なNode.jsサーバー向けに書かれたライブラリが、そのまま動くとは限りません。Next.jsをCloudflareへ出すときは、使用中のNext.js機能とCloudflare側の対応状況を確認します。

細かな要件や大規模化まで考えるならAWS

AWSには、EC2、Lambda、Amplify、S3、CloudFront、RDSなど、多数のサービスがあります。小さく始めることもできますが、どれを組み合わせるか、誰にどの権限を与えるか、通信をどう通すかまで決められます。

この自由度は、大規模なサービスや企業の要件では強みになります。初めての個人開発では、設定項目が多く、エージェントが作った構成を確認する範囲も広くなります。

AWSにも新規利用者向けのFree Planがあります。現在のFree Planは、最長6か月またはクレジットを使い切るまで利用できる仕組みです。AWSは「無料枠がない」のではなく、無料期間の終了後やPaid Planでの従量課金を管理する必要があります。

このシリーズでの選び方

  • 個人のNext.jsアプリを最短で公開したい:Vercel
  • API、D1、R2まで小さくまとめたい:Cloudflare
  • 細かなネットワークや企業向け要件がある:AWS

一つのサービスを永遠に使い続けると決める必要はありません。最初に確認できる範囲で始め、必要になった条件に合わせて移行を考えます。

Local、Preview、Production

同じアプリでも、目的ごとに環境を分けます。

localでの変更がGitHubへのpushとCIを通り、確認用Previewを経て利用者向けProductionへ進むデプロイの流れを示した図

環境 主に使う人 目的
Local 開発者 自分のパソコンで開発する
Preview / Development 開発者、確認者 公開前の変更を試す
Staging チーム内の確認者 本番に近い条件で確認する
Production 実際の利用者 正式にサービスを提供する

すべてのプロジェクトにStagingがあるとは限りません。小さな個人開発なら、Local、Preview、Productionだけの場合もあります。

環境ごとに、URL、データベース、APIキーを分けることが大切です。Preview環境から本番データベースへ接続すると、確認中のコードが本番データを書き換えてしまう可能性があります。

ブランチと環境を対応させる構成もあります。

  • Pull Request / featureブランチ: Preview
  • develop: DevelopmentまたはStaging
  • main: Production

これはよくある例であり、Next.jsやGitHubの固定ルールではありません。プロジェクトの設定を確認します。

CI/CDとは何か

デプロイの話では、CI/CDという言葉が頻繁に出てきます。

CIは、変更を自動で検査する

CIはContinuous Integrationの略です。コードがGitHubへ送られたときに、次のような検査を自動で行います。

  • テスト
  • 型チェック
  • Lint
  • セキュリティチェック
  • 本番用ビルド

自分のパソコンで一度成功しただけでなく、毎回同じ環境で確認できるのが利点です。

CDは、公開できる状態へ運ぶ

CDは、文脈によってContinuous DeliveryまたはContinuous Deploymentを指します。

  • Continuous Delivery:いつでも公開できるところまで自動で準備する
  • Continuous Deployment:検査に通った変更を自動で本番へ公開する

本番だけは人がボタンを押す構成ならDelivery、自動的に本番まで進む構成ならDeploymentに近くなります。

CI/CDは考え方です。GitHub Actionsは、その流れを実行できる仕組みの一つです。VercelやCloudflareのGit連携に、同じ役割の一部を任せることもできます。

GitHub Actionsを読む

GitHub Actionsの設定は、通常.github/workflows/にあるYAMLファイルへ書かれます。

  • .github/
    • workflows/
      • ci.yml
      • deploy.yml

よく出てくる言葉は次のとおりです。

  • workflow:自動処理全体
  • event/trigger:いつ開始するか
  • job:まとまった作業
  • step:job内の一つの手順
  • runner:処理を実行する一時的なコンピューター
  • action:再利用できる処理

たとえば、次のワークフローは、mainへpushされたときに検査とデプロイを行う形です。

name: deploy

on:
  push:
    branches: [main]

jobs:
  test-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: コードを取得する
        uses: actions/checkout@v4

      - name: Node.jsを用意する
        uses: actions/setup-node@v4
        with:
          node-version: 24
          cache: npm

      - name: パッケージを入れる
        run: npm ci

      - name: テストする
        run: npm test

      - name: ビルドする
        run: npm run build

      - name: デプロイする
        run: npm run deploy
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}

実際のコマンド、Node.jsのバージョン、secret名はプロジェクトごとに違います。この例をそのままコピーするのではなく、エージェントが作ったYAMLで次を確認します。

  • どのブランチで動くか
  • Pull Requestでは検査だけか、デプロイもするか
  • テストが失敗したらデプロイを止めるか
  • DevelopmentとProductionを取り違えていないか
  • 外部のactionをどのバージョンで使っているか
  • 本番デプロイに人の承認が必要か

Secrets and variables

GitHub ActionsからVercel、Cloudflare、AWSなどへデプロイするには、認証情報が必要になることがあります。その値をYAMLへ直接書いてはいけません。

GitHubでは、リポジトリの次の場所から登録できます。

  1. Settings
  2. Secrets and variables
  3. Actions

Variablesに置くもの

Variablesは、秘密にする必要のない設定値です。

  • リージョン名
  • プロジェクト名
  • 公開URL
  • 機能を有効にするフラグ

GitHub Actionsでは${{ vars.NAME }}のように参照します。

Secretsに置くもの

Secretsには、外へ出してはいけない値を置きます。

  • APIキー
  • デプロイトークン
  • データベース接続情報
  • 秘密鍵

GitHub Actionsでは${{ secrets.NAME }}のように参照します。登録後の値は、通常そのまま表示して確認できません。分からなくなった場合は、新しい値を登録します。

GitHubはsecretらしい値をログで隠しますが、どんな加工をしても必ず隠れるわけではありません。echoprintenvで表示しないことが基本です。

GitHubへ登録すれば全部へ届くわけではない

GitHub ActionsのSecrets、VercelのEnvironment Variables、CloudflareのSecrets、AWSの認証情報は、それぞれ別の保存場所です。

GitHubのsecretをワークフローへ登録しても、Vercelで動くNext.jsへ自動的に渡るわけではありません。デプロイ時だけ必要な認証情報と、デプロイ後のアプリが実行時に必要な値を分けて考えます。

デプロイするときだけ必要:

  • CloudflareやAWSへ書き込むためのトークン

アプリが動くたびに必要:

  • LLMのAPIキー、データベース接続情報

Development、Preview、Productionで同じsecretを使い回さず、環境ごとに分けます。本番用のトークンには、本番デプロイに必要な最小限の権限だけを与えます。

デプロイとデータベース変更

データベースを使うアプリでは、コードのデプロイとマイグレーションが一緒に出てきます。

  1. テスト
  2. バックアップや復元方法を確認
  3. マイグレーションを適用
  4. 新しいコードをデプロイ
  5. 動作確認

実際の順番は変更内容によって異なります。先に新しい列を追加してからコードを出す場合もあれば、古いコードと新しいコードの両方で動く移行期間を作る場合もあります。

大切なのは、コードを以前のバージョンへ戻しても、データベースが自動的に元へ戻るとは限らないことです。Cloudflareでも、WorkerのバージョンとD1などに保存されたデータは別に管理されます。

エージェントがマイグレーションをデプロイへ組み込んだら、次を確認します。

  • どの環境のデータベースが変わるか
  • 既存データが入った状態で成功するか
  • マイグレーション失敗時にデプロイを止めるか
  • 古いコードでも変更後のDBを読めるか
  • バックアップや復元方法があるか

Deploy successfulのあとに確認する

CIが緑になり、デプロイが成功しても、それだけでは利用者が使えるとは確認できません。

公開URL

  • URLが開くか
  • 独自ドメインを使う場合、正しいデプロイ先へ向いているか
  • HTTPSになっているか
  • ログインしていない利用者からも、想定した画面が見えるか

DNSの変更は反映に時間がかかることがあります。デプロイエラーとDNSの反映待ちを区別します。

主要な操作

  • 画面が表示されるか
  • フォームを送信できるか
  • APIが成功するか
  • ログインとログアウトが動くか
  • データが保存され、再読み込み後も残るか
  • アップロードした画像があとから開けるか

秘密情報

  • APIキーがブラウザ用JavaScriptへ含まれていないか
  • エラーメッセージに接続情報が出ていないか
  • GitHub Actionsやデプロイ先のログへsecretが出ていないか

ログ

公開画面で「エラーが起きました」と表示されても、それだけでは原因が分かりません。デプロイ先のログで、どの処理が失敗したかを確認します。

一方、ログへ利用者のパスワード、APIキー、入力した機密情報を残してはいけません。ログは原因調査に必要な情報だけを記録します。

戻せるようにしておく

新しいデプロイで問題が起きたときは、以前の正常なバージョンへ戻します。これをロールバックと呼びます。

確認しておきたいのは次の点です。

  • 以前のデプロイをどこで確認できるか
  • どの操作で以前の版へ戻せるか
  • ロールバックしても環境変数は合うか
  • データベース変更だけが残っても動くか
  • 戻したあとに主要な操作を再確認したか

「GitHubで古いcommitへ戻した」だけでは、デプロイ先の状態まで戻ったとは限りません。実際の公開URLとデプロイ履歴を確認します。

料金と上限を確認する

無料枠には、リクエスト数、処理時間、ビルド回数、保存容量などの上限があります。上限を超えたときに、処理が止まるサービスもあれば、従量課金へ移るプランもあります。

公開前に、次を確認します。

  • 現在のプラン
  • 無料枠または含まれる利用量
  • 超過したときに停止するか、課金されるか
  • 利用量を確認する画面
  • 予算通知や上限設定
  • 不要なPreviewや古いリソースが残っていないか

AWSをPaid Planで使う場合は、予算通知も設定します。CloudflareやVercelでも、利用量と料金の画面を定期的に確認します。

価格や無料枠は変わります。記事に書かれた数字だけで判断せず、実際に使う時点の公式料金ページを確認してください。

エージェントのデプロイ設定を確認する

デプロイを頼んだら、次の点を確認します。

  • Vercel、Cloudflare、AWSのどこへ出すのか
  • Local、Preview、Staging、Productionのどれか
  • どのブランチがどの環境へつながるか
  • npm run buildが成功しているか
  • デプロイ先のNode.jsバージョンは何か
  • 必要なSecretsとVariablesは何か
  • secretをコードやログへ出していないか
  • APIキーがブラウザへ含まれていないか
  • データとファイルをどこへ保存するか
  • マイグレーションはいつ、どのDBへ適用するか
  • テスト失敗時にデプロイを止めるか
  • 本番デプロイに承認が必要か
  • 以前の版へ戻す方法はあるか
  • 料金通知と利用上限は設定されているか
  • 公開URLで主要な操作を確認したか

エージェントには、次のように頼めます。

このデプロイで、どのブランチがどの環境へ公開されるか説明してください。 GitHub Actions、デプロイ先、データベースの順に整理してください。

デプロイに必要な環境変数を、公開してよいVariablesと、秘密にするSecretsへ分けてください。 値そのものは表示せず、登録先と用途だけを教えてください。

CIの成功だけで完了とせず、公開URLから主要な利用者操作を確認してください。 確認できたことと、認証などの理由で確認できなかったことを分けて報告してください。

このデプロイを以前の版へ戻した場合、コード、環境変数、データベースに何が残るか説明してください。 破壊的なマイグレーションがあれば、実行前に止めてください。

デプロイは、アプリを公開URLへ置くだけの作業ではありません。どのコードが、どの環境で、どの権限を使って動き、データをどこへ残すのかを決める作業です。そこまで説明できる状態なら、エージェントが作った設定を任せきりにせず、自分で確認できます。