AI で作ったアプリはどこに公開する? Vercel・Supabase・Cloudflare を料金と実デプロイで比べる

AIエージェント

ChatGPT や Claude Code にお願いすると、Web アプリは数分でできあがります。ところが「できたアプリをどこに置けば、URL を人に渡せるのか」で手が止まる人が多いです。候補としてよく名前が挙がるのが Vercel、Supabase、Cloudflare の 3 社ですが、この 3 つは「同じ土俵の競合」ではありません。

この記事では、3 社の役割の違いと料金プランを公式ドキュメントで整理したうえで、同じ小さなアプリを実際に 3 社へ載せて、何が起きるかを確かめます。さらに、ChatGPT や Claude の「コネクタ」から 3 社を操作できるのかも調べました。最後に「AI で作ったアプリを公開するなら、どれが向いているか」を結論として示します。

想定読者は、AI にコードを書いてもらった経験はあるけれど、デプロイ先を自分で選んだことがない方です。専門用語には短い説明を添えます。

この記事の確認範囲

  • 料金・制限・手順は 2026 年 10 月 1 日に各社の公式ページ(vercel.com/docs、supabase.com/docs、developers.cloudflare.com)で確認した内容です。価格は米ドル・税別です
  • 実デプロイに使った道具:Vercel CLI 62.1.0、Wrangler 4.145.0、Supabase CLI 2.119.0、Node.js 22.23、macOS(M5 Max)
  • 3 社とも無料プラン(Vercel Hobby、Cloudflare Workers Free、Supabase Free)で、同じアプリを本番 URL まで実際に載せました。画面・端末の記録はすべて本文に貼っています

まず、3 社の立ち位置を 1 枚で見てください。AI で作るアプリは「画面」「API」「保存」の 3 層でできていて、各社が自前で持っている層が違います。

AI で作ったアプリの 3 層(フロント・API・DB)と、Vercel・Cloudflare・Supabase がそれぞれ自前で持つ層を◎△✕で示した図。Supabase はフロントを持たず、Vercel は DB を持たない

図1:Vercel は画面と API、Cloudflare は 3 層すべて、Supabase は API と保存を持つ。「Vercel + Supabase」は公式ドキュメントが想定する定番の組み合わせ

先に結論

結論から書きます。評価の観点は「公開のしやすさ」「無料で続けられるか」「AI ツールから操作できるか」の 3 つです。

結論の図。1 位 Cloudflare Workers、2 位 Vercel、そして裏方として組み合わせる Supabase の 3 段で、それぞれの理由を短く示す

図9:AI ツールからの操作(MCP)は 3 社とも ChatGPT・Claude の公式一覧に載っていて差がつかない。差がつくのは「無料で商用できるか」と「DB が付いているか」

観点VercelCloudflare WorkersSupabase
役割画面と API を置く場所画面・API・DB を置く場所DB・ログイン・API の裏方(画面は置けない)
無料プランで商用利用不可(Hobby は非商用のみ)可(規約に禁止条項なし)可(ただし 1 週間無アクセスで停止)
最初の有料プランPro $20/月Paid $5/月Pro $25/月
得意なものNext.js、Git 連携、Preview URL静的サイト + 軽い API、無料枠の広さPostgres、Auth、RLS、pgvector
自前の DBなし(Marketplace で Neon / Supabase)D1 / KV / R2Postgres が本体
東京で動く関数リージョン hnd1 を選べる最寄りのエッジで自動プロジェクト・関数とも Tokyo あり
ChatGPT / Claude のコネクタ両方に公式掲載両方に公式掲載両方に公式掲載
向いている人Next.js で作った、Preview を人に見せたい無料のまま公開したい、API と DB を 1 社で済ませたいログインや投稿データが要る

一言でまとめると、「画面は Cloudflare か Vercel、裏方は Supabase」 が AI 製アプリの基本形です。Next.js で作ったなら Vercel、素の HTML や Vite・Astro なら Cloudflare が楽です。

3 社はそもそも何が違うのか

Vercel:Next.js の開発元が運営する「画面と API の置き場所」

Vercel は Next.js を作っている会社のホスティングサービスです。GitHub にコードを置いて Vercel に取り込むと、push するたびにビルドして公開します。本番ブランチ(main)以外への push は Preview Deployment になり、ブランチごとに別 URL が出ます。

AI で作ったアプリを人に見せる場面では、この Preview URL が便利です。一方で、Vercel 自体にはデータベースがありません。かつてあった Vercel Postgres と Vercel KV は Marketplace のパートナー(Neon、Supabase、Upstash など)に移行済みで、ダッシュボードから接続する形になっています。

Vercel の料金ページ。Hobby $0、Pro $20/月、Enterprise はカスタムの 3 列

Vercel の料金ページ(2026-10-01 撮影)。Pro は「$20 分の利用クレジット込み」というクレジット制

項目Hobby($0)Pro($20/月〜)Enterprise
商用利用不可(非商用・個人のみ)可可
メンバー1 人のみ$20/月/人(閲覧のみは無料)カスタム
含まれる使用量帯域 100GB、関数呼び出し 100 万回、Active CPU 4 時間など$20 分のクレジットを全リソース横断で消費。CDN は 1TB・100 万リクエスト込みカスタム
超過したら課金されず、その機能が 30 日停止クレジット消費後は従量課金契約
デプロイ回数100 回/日6,000 回/日24,000 回/日
関数のタイムアウト300 秒既定 300 秒、最大 800 秒同左
関数リージョン1 つ(東京 hnd1 を選べる)最大 5 つ全リージョン
Cron1 日 1 回まで毎分可毎分可
組織の非公開リポジトリ不可可可
使いすぎ防止不要(課金なし)Spend Management(既定 $200 で本番停止)あり

出典は Vercel の Pricing、Hobby plan、Pro plan、Limits です。

気づき:Hobby の「非商用のみ」は、公式の Fair Use Guidelines に具体例つきで書かれています。広告(AdSense)を貼る、商品を売る、受託で作ったサイトを置く、いずれも対象です。「寄付のお願い」だけは商用に当たりません。AI で作ったサービスで収益を考えるなら、最初から Pro を見ておく必要があります。

Cloudflare:画面も API も DB も 1 社で揃う「エッジの置き場所」

Cloudflare Workers は、世界中のデータセンター(エッジ)でコードを動かすサービスです。静的ファイルを配信する Static Assets、SQLite 互換の D1、キーバリューの KV、S3 互換の R2 が同じアカウントで使えます。設定ファイル wrangler.jsonc 1 枚に「画面はどのフォルダ」「API はどのファイル」「DB はどれ」をまとめて書きます。

以前は静的サイト向けに Cloudflare Pages という別製品がありましたが、現在の公式ドキュメントは「新規は Workers で始める」と案内しています。AI が古い知識で wrangler pages deploy を出してきたら、Workers の手順に読み替えてください。

Cloudflare Workers の料金表。Free は 10 万リクエスト/日・CPU 10ms、Standard は月 1,000 万リクエスト込み

Cloudflare Workers の料金表(2026-10-01 撮影)。Paid の CPU 時間は 1 リクエスト既定 30 秒、最大 5 分

項目Workers Free($0)Workers Paid($5/月〜)Enterprise
商用利用可(規約に禁止なし。カード情報の自前処理は禁止)可可(SLA あり)
Worker のリクエスト10 万回/日(超過で 1027 エラー)1,000 万回/月込み、+$0.30/100 万回契約
CPU 時間10ms/リクエスト3,000 万 ms/月込み。1 回 30 秒〜5 分契約
静的ファイルの配信無料・無制限無料・無制限無料・無制限
帯域(egress)無料無料無料
D1読み 500 万行/日、書き 10 万行/日、5GB、1 DB 500MB読み 250 億行/月、書き 5,000 万行/月、1 DB 10GB引き上げ可
KV / R2KV 1GB、R2 10GB従量従量
Git 連携ビルド3,000 分/月6,000 分/月同左
ログ保持3 日7 日Logpush
Workers AI1 万 Neurons/日同左 + 従量同左
カスタムドメインCloudflare で管理するドメインが必要同左同左

出典は Cloudflare の Workers Pricing、Limits、D1 Pricing、Self-Serve Subscription Agreement です。

気づき:Free の「CPU 10ms」は、プログラムが実際に計算している時間だけを数えます。外部の AI API を呼んで応答を待っている時間は含まれません。ただし Next.js のサーバーサイドレンダリングのように、1 リクエストで重い処理をする構成は厳しいです。Paid($5)にすると 30 秒に広がり、AI アプリの現実的な選択肢になります。

Supabase:画面は置けない。Postgres と Auth の「裏方」

Supabase は Firebase の代替を目指すオープンソースのバックエンド基盤です。中身は Postgres(DB)、Auth(ログイン)、Storage(ファイル)、Edge Functions(Deno で動く API)、Realtime(WebSocket)です。pgvector でベクトル検索もできます。

ここで大事なのは、Supabase はフロントエンドを配信しないことです。公式ドキュメントには、Edge Functions が HTML を返しても text/plain に書き換えると書かれています。カスタムドメインの説明にも「フロントエンドのホスティング用ではない」と明記されています。画面は Vercel や Cloudflare に置き、そこから Supabase を呼ぶ構成が公式の想定です。

Supabase の料金ページ。Free $0、Pro $25/月〜、Team $599/月〜、Enterprise はカスタムの 4 列

Supabase の料金ページ(2026-10-01 撮影)。Free の脚注に「1 週間非アクティブで一時停止、有効プロジェクト 2 つまで」とある

項目Free($0)Pro($25/月〜)Team($599/月〜)Enterprise
コンピュートNano(共有 CPU・500MB RAM)$10 分のクレジット込み(Micro 1 台分)。2 プロジェクト目から +$10/月同左カスタム
DB サイズ500MB(超えると読み取り専用)8GB/プロジェクト、+$0.125/GB同左カスタム
一時停止1 週間無アクセスで停止なしなしなし
プロジェクト数有効 2 つまで無制限無制限無制限
MAU(ログインユーザー)5 万10 万、+$0.00325/人同左カスタム
Edge Functions50 万回200 万回、+$2/100 万回同左カスタム
帯域(egress)5GB250GB、+$0.09/GB同左カスタム
バックアップなし日次 7 日分日次 14 日分カスタム
Branching(PR ごとの DB)なし$0.01344/ブランチ/時同左同左
カスタムドメインなし$10/月同左同左
ログ保持1 日7 日28 日90 日
使いすぎ防止不要Spend Cap 既定 ON同左同左

出典は Supabase の Pricing、Free project pausing、Compute and Disk、Edge Functions Limits です。

気づき:Pro の $25 は組織単位の料金です。1 プロジェクト目の Micro($10)はクレジットで相殺され、2 プロジェクト目から $10 ずつ増えます。公式の計算例は「2 プロジェクトで $35/月」です。

無料枠で「止まる」条件を並べる

AI で作って公開したあと、最初にぶつかる壁を 3 社で並べました。どれも「お金が勝手に請求される」のではなく、「止まる」「できない」の形で現れます。

3 社の無料枠で止まる・できない条件の比較。Vercel は非商用と 100 デプロイ/日、Cloudflare は 10 万リクエスト/日と CPU 10ms、Supabase は 1 週間停止と 2 プロジェクト

図8:赤字が「止まる・できない」、緑字が「無料でも十分」。下段は最初の有料プランで何が変わるか

どれを選ぶか:判断フロー

置き場所の判断フロー。Q1 Next.js の SSR を使うか、Q2 ログインや保存が要るか、Q3 無料のまま商用で公開したいか、の 3 問で分岐

図2:Q2 で「はい」でも画面の置き場所は Q1・Q3 で決める。多くの AI 製アプリは「画面 = Vercel か Cloudflare」+「裏方 = Supabase」の 2 社構成になる

もう少し具体的に、作ったものの種類で分けると次のようになります。

作ったものおすすめ理由
素の HTML / Vite / Astro の静的サイトCloudflare Workers(Free)静的配信は無料・無制限。商用でも可
Next.js(App Router、Server Actions)Vercel開発元。設定ゼロで SSR・ISR・画像最適化が動く。Cloudflare は vinext(ベータ)経由
フォームや AI API を呼ぶ API 付きの SPACloudflare WorkersWorker 1 本で API、D1 で保存。Free でも 10 万回/日
ログインが要る、ユーザーごとのデータがあるSupabase + 画面は上のどちらかAuth と Postgres と RLS が揃う。Free で MAU 5 万
収益化する(広告・課金)Cloudflare Free か Vercel ProVercel Hobby は商用不可。Cloudflare は Free でも可(カード情報は Stripe などへ)
公開デモを放置するCloudflare か VercelSupabase Free は 1 週間でプロジェクトが止まる
長い処理(数分の AI 生成)Vercel Pro(800 秒)か Cloudflare Paid(CPU 5 分)Free は Vercel 300 秒、Cloudflare CPU 10ms

検証:同じアプリを 3 社に載せる

ここからは実際に手を動かします。検証用に「ひとことボード」という小さなアプリを用意しました。入力欄に一言を書いて投稿すると一覧に並ぶ、掲示板の最小形です。画面は 3 ファイル(HTML・JS・CSS)だけで、フレームワークは使っていません。

検証構成の図。共通の画面を、A Vercel(Functions + メモリ→Supabase)、B Cloudflare(Worker + D1)、C Supabase(Edge Function + Postgres)の 3 経路に載せる

図3:API は /api/notes(GET で一覧、POST で追加)だけ。違いは「API をどこで動かし、どこに保存するか」。画面には配置先と保存先を表示して、どこで動いたか分かるようにした

画面側の JavaScript は、API の場所を切り替えられるようにしてあります。Supabase の Edge Function のように別のドメインで動く API を呼ぶときは、URL のクエリで ?api=... を渡します。

// shared-ui/app.js(抜粋)
// 既定は同じオリジンの /api/notes。別オリジンの API は ?api= で切り替える
const API = new URLSearchParams(location.search).get('api') || '/api/notes';

async function load() {
  const r = await fetch(API);
  const data = await r.json();
  // 「配置先: Vercel Functions / hnd1(メモリ)」のように、どこで動いたかを表示する
  document.querySelector('#where').textContent = `配置先: ${data.platform}(${data.storage})`;
  document.querySelector('#list').innerHTML = data.notes.map(n =>
    `<li><span>${escapeHtml(n.text)}</span><time>${new Date(n.created_at).toLocaleString('ja-JP')}</time></li>`).join('');
}

コードは 1 つの GitHub リポジトリに vercel/、cloudflare/、supabase/ の 3 フォルダで置きました(非公開リポジトリ)。

Vercel:GitHub に push して Import するだけ

Vercel 版は public/ に画面、api/notes.js に API を置きます。api/ フォルダに置いたファイルは自動で Vercel Functions(サーバーレス関数)になります。Vercel には DB がないので、環境変数で Supabase の接続先が渡されたときだけ Postgres に保存し、無ければ関数のメモリに置く作りにしました。「メモリに置くと何が起きるか」を見るためです。

// vercel/api/notes.js(抜粋)
import { createClient } from '@supabase/supabase-js';

const memory = [];                                   // 関数インスタンスの中だけで生きる配列
const region = process.env.VERCEL_REGION || 'local'; // 実行リージョン(hnd1 など)
const supabase = process.env.SUPABASE_URL && process.env.SUPABASE_SECRET_KEY
  ? createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SECRET_KEY)
  : null;                                            // 環境変数が無ければメモリ保存

export default async function handler(req, res) {
  const storage = supabase ? 'Supabase Postgres' : 'メモリ(非永続)';
  const platform = `Vercel Functions / ${region}`;
  if (req.method === 'GET') {
    let notes = memory;
    if (supabase) {
      const { data } = await supabase.from('notes').select('id,text,created_at')
        .order('created_at', { ascending: false }).limit(20);
      notes = data;
    }
    return res.status(200).json({ platform, storage, notes: notes.slice(0, 20) });
  }
  // POST は省略(text を検証して memory か Supabase に追加)
}

関数を東京で動かすため、vercel.json にリージョンを 1 行書きます。指定しないと米国東部(iad1)で動きます。

{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "regions": ["hnd1"]
}

手順は次のとおりです。

Vercel の手順図。GitHub にリポジトリ作成、vercel.com/new で Import、Root Directory 指定、Deploy、本番 URL は公開、生成 URL はログイン保護、関数は hnd1 で動いた、の 7 段

図4:push から本番 URL まで約 1 分。URL と応答コードは実測

  1. GitHub にリポジトリを作って push します。
# 検証アプリのフォルダで実行。非公開リポジトリを作って push する
gh repo create Takuya-ops/hitokoto-board --private --source=. --remote=origin --push
  1. vercel.com/new を開き、リポジトリ一覧から hitokoto-board の Import を押します。Vercel の GitHub アプリが入っていれば一覧に出ます。
  2. Root Directory を vercel/ にします。1 リポジトリに 3 構成を入れたためです。Framework Preset は「Other」のままで構いません。
Vercel の New Project 画面。Importing from GitHub に Takuya-ops/hitokoto-board と main と vercel、Root Directory に vercel、Application Preset に Other、下に Deploy ボタン

Root Directory を vercel にしたところ。プロジェクト名は自動で hitokoto-board-vercel になった

  1. Deploy を押します。ビルドは 11 秒、画面が切り替わるまで約 1 分でした。
Vercel の Congratulations 画面。You just deployed a new project to takuya-ops' projects と、デプロイしたアプリのプレビュー

デプロイ完了画面。下には「Turn Your Agent into a Vercel Expert」として Vercel プラグインの導入コマンドが出る

  1. 本番 URL を開いて投稿してみます。画面の「配置先」が Vercel Functions / hnd1(メモリ(非永続)) になり、東京リージョンで動いたことが分かります。
本番 URL で開いたひとことボード。配置先 Vercel Functions / hnd1(メモリ(非永続))と表示され、ブラウザからの投稿と curl からの投稿が 2 件並ぶ

本番 URL(hitokoto-board-vercel.vercel.app)でブラウザから投稿したところ

curl で確認した応答はこうでした。x-vercel-id ヘッダーに hnd1 が入っています。

curl -s -i https://hitokoto-board-vercel.vercel.app/api/notes | grep -E '^HTTP|x-vercel-id|^\{'
HTTP/2 200
x-vercel-id: hnd1::hnd1::nbnrq-1790846918510-a31e1004efb0
{"platform":"Vercel Functions / hnd1","storage":"メモリ(非永続)","notes":[]}
Vercel の Deployments 画面。1 件のデプロイが Ready 11s、Production、main、3m ago と表示されている

Deployments 画面。「Deployment Retention is enabled」の注記は、Hobby が直近 3 本しかデプロイを保持しなくなった 2026 年 9 月の変更によるもの

実測で分かったこと(Vercel)

  • 本番 URL だけが公開で、生成 URL はログインが要る。hitokoto-board-vercel.vercel.app は 200 で開けましたが、hitokoto-board-vercel-takuya-ops-projects.vercel.app と、コミットごとの ...-ep2c8jul2-...vercel.app は 302 で Vercel のログイン画面(SSO)に飛びました。Deployment Protection が新規プロジェクトで既定 ON だからです。AI エージェントや友人に Preview を見せるときは、共有リンク(Hobby は 1 本)か本番 URL を使います
  • メモリ保存は 12 分で消えた。投稿直後と 70 秒後は 2 件とも残っていましたが、約 12 分後に GET すると notes: [] でした。関数のインスタンスが入れ替わると消えます。Vercel に DB は無いので、保存したいデータは Marketplace の Neon や Supabase に置きます
  • リージョンは自分で指定する。vercel.json の 1 行で hnd1 になりました。Hobby でも東京は選べます(1 リージョンのみという制限で、場所の制限ではありません)

CLI でデプロイする場合は、公式ドキュメントの手順はこうです(今回は Git 連携で行ったため未実施)。

npm i -g vercel        # Vercel CLI を入れる(2026-10-01 時点で 62.1.0)
vercel login           # ブラウザで認証
vercel link            # フォルダをプロジェクトに紐付け(無ければ作成)
vercel                 # Preview デプロイ
vercel --prod          # 本番デプロイ

Cloudflare:wrangler.jsonc 1 枚で画面・API・DB を決める

Cloudflare 版は public/ が Static Assets、src/index.js が Worker、migrations/ が D1 のテーブル定義です。設定ファイルはこれだけです。

// cloudflare/wrangler.jsonc
{
  "name": "hitokoto-board",
  "main": "src/index.js",                 // API(Worker)
  "compatibility_date": "2026-09-01",
  "assets": { "directory": "./public" },  // 画面(静的ファイル)。一致するファイルがあれば Worker を通さず返す
  "observability": { "enabled": true },   // Workers Logs を有効化
  "d1_databases": [
    { "binding": "DB", "database_name": "hitokoto-board",
      "database_id": "REPLACE_AFTER_CREATE", "migrations_dir": "migrations" }
  ]
}

Worker は /api/notes だけを処理します。それ以外のパスは静的ファイルが先に返るので、Worker には届きません。

// cloudflare/src/index.js(抜粋)
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    if (url.pathname !== '/api/notes') return new Response('Not found', { status: 404 });
    const platform = `Cloudflare Workers / ${request.cf?.colo || 'local'}`; // colo = 処理したデータセンター
    if (request.method === 'GET') {
      const { results } = await env.DB.prepare(
        'SELECT id, text, created_at FROM notes ORDER BY id DESC LIMIT 20').all();
      return Response.json({ platform, storage: 'D1 (SQLite)', notes: results });
    }
    // POST は省略(text を検証して INSERT)
  },
};
Cloudflare の手順図。ローカルで先に動かす、wrangler login、D1 作成、本番にテーブル作成、wrangler deploy、URL が出る、以後の更新、の 7 段

図5:手順 1〜6 をこの Mac で実施。7 の Git 連携(Workers Builds)は公式ドキュメントの案内

手順 1:ローカルで動かす(ログイン不要)

Cloudflare の良いところは、ログインしなくてもローカルで本番と同じ構成を試せることです。D1 もローカルの SQLite として動きます。

cd cloudflare
npm install                                                 # wrangler をプロジェクトに入れる
npx wrangler d1 migrations apply hitokoto-board --local     # ローカル D1 にテーブルを作る
npx wrangler dev                                            # http://localhost:8787 で起動
# 別の端末から API を叩く
curl -s -X POST localhost:8787/api/notes -H 'content-type: application/json' \
  -d '{"text":"ローカルの wrangler dev から投稿"}'
curl -s localhost:8787/api/notes
{"ok":true}
{"platform":"Cloudflare Workers / NRT","storage":"D1 (SQLite)","notes":[{"id":1,"text":"ローカルの wrangler dev から投稿","created_at":"2026-10-01T09:22:09.041Z"}]}
ローカルの wrangler dev で開いたひとことボード。配置先 Cloudflare Workers / NRT(D1 (SQLite))と表示され、投稿が 1 件ある

ローカル実行。request.cf.colo が NRT(成田)と返るのは、wrangler dev がローカルでも Cloudflare 経由の値を模擬するため

手順 2〜7:本番へ

npx wrangler login                                          # ブラウザが開き、OAuth で許可する
npx wrangler d1 create hitokoto-board --location=apac       # 本番の D1 を作る(アジア太平洋を優先)
# → 表示された database_id を wrangler.jsonc の REPLACE_AFTER_CREATE に貼る
npx wrangler d1 migrations apply hitokoto-board --remote    # 本番 D1 にテーブルを作る
npx wrangler deploy                                         # 画面 + Worker をまとめてデプロイ

wrangler login はブラウザが開いて Cloudflare の許可画面になり、「Allow」を押すと端末に Successfully logged in. と出ます。D1 の作成は数秒で終わり、database_id が表示されます。--remote のマイグレーションは「本番に適用してよいか」を y/n で聞いてきます。

デプロイの様子を端末ごと録画しました。マイグレーションの確認、デプロイ、直後の投稿までで約 50 秒です。

端末の録画。wrangler d1 migrations list で適用済みを確認し、wrangler deploy で静的ファイル 3 点と Worker をアップロードして workers.dev の URL が表示され、curl で投稿と一覧取得が成功する

wrangler deploy は約 5 秒。表示された URL に curl で POST と GET をして、D1 に保存されたことを確認

デプロイ後に表示された URL は https://hitokoto-board.hitokoto-board-cloudflare.workers.dev でした。<自分のサブドメイン> の部分は、初回デプロイ時にアカウントへ自動で割り当てられます。

curl -s -i https://hitokoto-board.hitokoto-board-cloudflare.workers.dev/api/notes | grep -E '^HTTP|^cf-ray|^\{'
HTTP/2 200
cf-ray: a43c1b236fc8e37d-NRT
{"platform":"Cloudflare Workers / NRT","storage":"D1 (SQLite)","notes":[]}
Cloudflare ダッシュボードの Workers & Pages。hitokoto-board が 1 件あり、右の Usage に Requests today 0 / 100,000 と表示されている

Workers & Pages 画面。右側の Usage に Free の上限「100,000 リクエスト/日」が表示される。Subdomain の欄で workers.dev のサブドメインを変えられる

workers.dev の本番 URL で開いたひとことボード。配置先 Cloudflare Workers / NRT(D1 (SQLite))と表示され、ブラウザからの投稿 1 件と curl からの投稿 2 件が並ぶ

本番 URL でブラウザから投稿したところ。cf-ray ヘッダーと画面の「NRT」は成田のデータセンターで処理されたことを示す

実測で分かったこと(Cloudflare)

  • URL が使えるまで約 1 分かかった。デプロイ直後の curl は接続エラーで、約 30 秒後に 200 になりました。初めて workers.dev のサブドメインが作られたときは、DNS の反映を少し待ちます
  • 設定ファイル 1 枚で 3 層が揃う。wrangler.jsonc の assets(画面)、main(API)、d1_databases(保存)を書いただけで、画面・API・DB が同じ URL に乗りました。アップロードされたのは静的ファイル 3 点と 1.16KB の Worker です
  • リージョンは選ばなくても日本で動く。request.cf.colo が NRT(成田)でした。Vercel のように設定で東京を指定する必要がありません
  • --remote の操作は確認が入る。d1 migrations apply --remote は y/n を聞いてくるので、自動化するときは --yes などの非対話オプションを確認します

以後の更新は wrangler deploy をもう一度実行するだけです。GitHub に push するだけで自動化したい場合は、ダッシュボードの Workers Builds(Git 連携、Free は 3,000 分/月)を設定します(今回は未実施)。

Supabase:裏方を用意して、Vercel の画面からつなぐ

Supabase 版は、テーブル定義(migration)と Edge Function の 2 つです。画面は持てないので、Vercel に置いた画面から Edge Function を呼びます。

テーブルには RLS(Row Level Security、行レベルセキュリティ) を有効にし、公開キーからは読み取りだけ許可します。書き込みは Edge Function の中で secret キーを使って行います。

-- supabase/supabase/migrations/20261001000000_notes.sql
create table if not exists public.notes (
  id bigint generated always as identity primary key,
  text text not null check (char_length(text) <= 60),
  created_at timestamptz not null default now()
);
alter table public.notes enable row level security;                     -- RLS を有効化
create policy "notes are readable by anyone" on public.notes for select using (true);  -- 読み取りだけ誰でも可
// supabase/supabase/functions/notes/index.ts(抜粋)
import { createClient } from "npm:@supabase/supabase-js@2";

Deno.serve(async (req) => {
  // Edge Function の中では secret キーを使う(ブラウザには出さない)
  const supabase = createClient(Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!);
  const platform = `Supabase Edge Functions / ${Deno.env.get("SB_REGION") ?? "?"}`;
  if (req.method === "GET") {
    const { data } = await supabase.from("notes").select("id,text,created_at")
      .order("created_at", { ascending: false }).limit(20);
    return json({ platform, storage: "Supabase Postgres", notes: data });
  }
  // POST と CORS ヘッダーは省略
});
Supabase の手順図。プロジェクト作成、CLI でログインと link、db push、functions deploy、画面は別の場所に置く、Vercel の関数からも同じ DB を使う、鍵の置き場所、の 7 段

図6:Supabase は「置き場所」ではなく「裏方」。画面は Vercel の本番 URL に ?api= を付けて Edge Function を呼ぶ

プロジェクトはダッシュボードの「New project」でも作れますが、今回は CLI だけで進めました。supabase login はブラウザが開いて確認コードを表示し、端末に貼ると You are now logged in. と出ます。

brew install supabase/tap/supabase          # Supabase CLI(2026-10-01 時点で 2.119.0)
supabase login                              # ブラウザでログイン(アクセストークンを取得)
supabase orgs list                          # 組織の ID を確認
supabase projects create hitokoto-board --org-id <組織の ID> --db-password <DB パスワード> --region ap-northeast-1
cd supabase
supabase link --project-ref <プロジェクトの ref>   # ローカルのフォルダをプロジェクトに紐付け
supabase db push                            # migration を本番 DB に適用(notes テーブル + RLS)
supabase functions deploy notes             # Edge Function を公開

実行結果はこうでした。プロジェクト作成は約 20 秒で ACTIVE_HEALTHY になり、migration の適用と関数のデプロイもそれぞれ数十秒です。

Created a new project at https://supabase.com/dashboard/project/kxqhmhcgtrcgetwtpglq
{"ref":"kxqhmhcgtrcgetwtpglq","name":"hitokoto-board","region":"ap-northeast-1","status":"ACTIVE_HEALTHY"}
Applying migration 20261001000000_notes.sql...
{"migrations":["20261001000000_notes.sql"],"message":"Finished supabase db push."}
Deploying Function: notes (script size: 757 kB)
{"functions":["notes"],"dashboard_url":"https://supabase.com/dashboard/project/kxqhmhcgtrcgetwtpglq/functions","message":"Deployed Functions."}
Supabase の Table Editor。notes テーブルに id・text・created_at の 3 列があり、2 行のデータが入っている。右上に RLS policy 1 と表示

Table Editor。右上の「1 RLS policy」が migration で作った読み取り許可のポリシー。この画面から行の追加や SQL も実行できる

Supabase の Edge Functions 画面。notes 関数が 1 つあり、URL が https://kxqhmhcgtrcgetwtpglq.supabase.co/functions/v1/notes と表示されている

Edge Functions 画面。関数の URL は https://<ref>.supabase.co/functions/v1/<関数名>

関数を curl で叩くと、東京リージョン(ap-northeast-1)で動き、Postgres に保存されました。

curl -s -X POST https://kxqhmhcgtrcgetwtpglq.supabase.co/functions/v1/notes \
  -H 'content-type: application/json' -d '{"text":"Supabase Edge Function に直接 POST"}'
curl -s https://kxqhmhcgtrcgetwtpglq.supabase.co/functions/v1/notes
{"ok":true}
{"platform":"Supabase Edge Functions / ap-northeast-1","storage":"Supabase Postgres","notes":[{"id":1,"text":"Supabase Edge Function に直接 POST","created_at":"2026-10-01T14:10:22.74286+00:00"}]}

画面は Supabase に置けないので、Vercel に置いた画面から ?api= で関数を呼びます。URL は https://hitokoto-board-vercel.vercel.app/?api=https://kxqhmhcgtrcgetwtpglq.supabase.co/functions/v1/notes です。

Vercel の本番 URL で開いたひとことボードが、配置先 Supabase Edge Functions / ap-northeast-1(Supabase Postgres)と表示し、ブラウザからの投稿と curl からの投稿が並ぶ

画面は Vercel、API と保存は Supabase。これが「画面 = Vercel、裏方 = Supabase」の形。ブラウザからの投稿は CORS ヘッダーを関数が返しているので通る

実測で分かったこと(Supabase)

  • フロントが無くても「アプリ」は完成する。画面を別の場所(今回は Vercel)に置けば、ログインも保存も Supabase 側で完結します。逆に言うと、Supabase だけでは URL を人に渡せません
  • 公開 API にするには設定が要る。Edge Functions は既定で JWT(ログイン済みの証明)を要求します。config.toml に verify_jwt = false を書いた関数だけが、誰でも呼べる API になります
  • 秘密の鍵を自分で扱わずに済んだ。Edge Function の中では SUPABASE_URL と SUPABASE_SERVICE_ROLE_KEY が最初から環境変数として入っています。秘密の鍵をコピーして貼る作業が無いので、鍵の漏えいが起きにくい構成です
  • 新旧の API キーが両方ある。作ったばかりのプロジェクトでも、supabase projects api-keys には legacy の anon / service_role と、新しい publishable / secret の 4 つが並びました。移行期間中なので、新しい方(sb_publishable_ / sb_secret_)を使います
  • 放置すると 1 週間で止まる。Free プロジェクトなので、この記事の検証 URL も 1 週間アクセスが無ければ一時停止します

さらに Vercel の関数側にも SUPABASE_URL と SUPABASE_SECRET_KEY を環境変数として登録すると、Vercel の関数の保存先が「メモリ」から「Supabase Postgres」に変わり、画面も API も Vercel、保存だけ Supabase という構成になります。登録は Vercel のプロジェクト設定「Environment Variables」から行います(secret キーを扱う作業のため、今回は本人の操作に委ね、記事では未実施です)。

ChatGPT・Claude から 3 社を操作する

3 社とも MCP(Model Context Protocol) のリモートサーバーを公式に用意しています。MCP は、AI ツールが外部サービスの機能を「道具」として呼ぶための共通の約束事です。認証は OAuth で、ブラウザでログインして「許可」を押すだけです。API キーを手で貼る必要はありません。

接続構成の図。左に Claude.ai、ChatGPT、Claude Code、Codex CLI、中央に OAuth 認可、右に mcp.vercel.com、mcp.supabase.com/mcp、bindings.mcp.cloudflare.com/mcp

図7:つなぎ方は 3 社とも同じ。違うのは「つないだ先で何ができるか」と「権限の絞り方」

Claude.ai と ChatGPT の両方で、実際に一覧を検索して掲載を確認しました。

Claude.ai のコネクタ一覧で Vercel、Supabase、Cloudflare を検索した結果。それぞれ公式(Anthropic 確認済み)のカードが先頭に出る

Claude.ai の「カスタマイズ > コネクタ > 探索」。Vercel と v0、Supabase、Cloudflare Developer Platform が公式として掲載

ChatGPT のプラグイン一覧で Vercel、Supabase、Cloudflare を検索した結果。Vercel、Supabase、Cloudflare のカードが出る

ChatGPT の「カスタマイズ > プラグイン」。Cloudflare は「Manage Cloudflare resources」と「platform guidance with official MCP」の 2 種が公式

サービスサーバー URLClaude.ai / DesktopChatGPTClaude CodeCodex CLI
Vercelhttps://mcp.vercel.com一覧に「Vercel」一覧に「Vercel」claude mcp add --transport http vercel https://mcp.vercel.comcodex mcp add vercel --url https://mcp.vercel.com
Supabasehttps://mcp.supabase.com/mcp一覧に「Supabase」(32 ツール)一覧に「Supabase」claude mcp add --transport http supabase "https://mcp.supabase.com/mcp"codex mcp add supabase --url "https://mcp.supabase.com/mcp"
Cloudflarehttps://bindings.mcp.cloudflare.com/mcp ほか 17 種一覧に「Cloudflare Developer Platform」(23 ツール)一覧に「Cloudflare」/plugin marketplace add cloudflare/skills → /plugin install cloudflare@cloudflarecodex mcp add cloudflare --url https://mcp.cloudflare.com/mcp

Claude Code と Codex CLI は、追加したあとに /mcp を実行するとブラウザで認可が走ります。Claude.ai のコネクタは Anthropic のクラウドからサーバーに接続するため、公開 URL のサーバーしか登録できません(localhost は不可)。ChatGPT のプラグインは Web 版・有料プラン向けで、書き込み系のツールは既定で確認ダイアログが出ます。

つないだ先でできること

  • Vercel:プロジェクト・デプロイ・ランタイムログの確認、保護された Preview URL の取得。2026 年 7 月からは deploy_to_vercel(ファイルからのデプロイ)と購入まで可能になり、読み取り専用ではなくなりました
  • Supabase:SQL 実行、migration 適用、Edge Functions のデプロイ、ログ、Security Advisor。URL に ?project_ref=<id>&read_only=true を付けると、1 プロジェクト・読み取り専用に絞れます
  • Cloudflare:KV / D1 / R2 の作成、Workers のデプロイ、ログ、ドキュメント検索。用途別にサーバーが分かれており、まずは docs.mcp.cloudflare.com/mcp(ドキュメント)から試すのが安全です

気づき:3 社とも公式ドキュメントが同じ警告を書いています。つないだ AI には あなたと同じ権限 が渡ること、外部の文章(チケット本文や Web ページ)に仕込まれた指示で勝手に操作される プロンプトインジェクション の危険があること、ツール実行の確認を切らないこと、です。Supabase は「本番 DB には read_only で、開発用プロジェクトか Branching を使う」とまで書いています。

チャットから直接デプロイする道もあります。Vercel の v0 はチャットの「Publish」で本番に出せ、Codex の Vercel プラグインは「プレビューをデプロイして URL をちょうだい」で Preview URL を返します。Cloudflare には「Deploy to Cloudflare」ボタン(公開リポジトリ限定)があり、wrangler の設定を読んで D1 や KV を自動で作ります。

つまずきやすい点と対処

症状原因対処
Vercel の Preview URL を開くとログイン画面になるDeployment Protection が既定 ON本番 URL を使う、共有リンクを発行する、Settings > Deployment Protection で範囲を変える
Vercel で投稿したデータが消える関数のメモリに置いているMarketplace の Neon / Supabase をつなぐ(vercel install supabase)
Vercel で「Hobby accounts are limited to daily cron jobs」とデプロイが失敗Hobby の Cron は 1 日 1 回までスケジュールを 0 10 * * * のように 1 日 1 回にするか Pro
Vercel の関数が遅い既定リージョンが米国 iad1vercel.json に "regions": ["hnd1"]
Cloudflare で wrangler pages deploy が見つからない、Pages の案内と違う新規は Workers(Static Assets)が公式方針assets.directory を書いて wrangler deploy
Cloudflare Free で 1027 エラーWorker のリクエストが 10 万回/日を超えた静的ファイルは Worker を通さない(run_worker_first を /api/* に限定)、Paid $5
Cloudflare で fs や crypto が無いと言われるnodejs_compat が無効compatibility_date を 2026-08-04 以降にするか compatibility_flags: ["nodejs_compat"]
Supabase の Edge Function で HTML が text/plain になるEdge Functions は HTML 配信非対応画面は Vercel / Cloudflare に置く
Supabase のプロジェクトが開けない(paused)Free は 1 週間無アクセスで一時停止ダッシュボードから Restore。放置するデモは Pro
Supabase で誰でも全データが読めるRLS が無効テーブルで RLS を有効化し、ポリシーを書く。Security Advisor で確認
MCP をつないだ AI が勝手に本番を触りそうで怖い権限がアカウント全体Supabase は read_only=true と project_ref、Cloudflare は OAuth 時に権限を絞る、確認ダイアログを切らない

まとめ

  • 3 社は競合ではなく役割が違います。Vercel は画面と API、Cloudflare は画面・API・DB、Supabase は DB・ログイン・API の裏方です
  • 無料で商用公開したいなら Cloudflare Workers。静的配信は無制限で、D1 も付いてきます。Next.js で作ったなら Vercel が最も楽ですが、Hobby は非商用限定です
  • ログインや投稿データが要るなら Supabase を裏方に。画面は Cloudflare か Vercel に置きます。Supabase Free は 1 週間無アクセスで止まる点だけ注意です
  • ChatGPT・Claude のコネクタは 3 社とも公式一覧に載っており、ここで差はつきません。つないだ AI には自分と同じ権限が渡るので、read_only と確認ダイアログを使います
  • 実デプロイでは、Vercel は push から約 1 分、Cloudflare は wrangler deploy 約 5 秒(URL の反映に約 1 分)、Supabase はプロジェクト作成から関数公開まで数分でした。Vercel の生成 URL は既定でログイン保護、関数のメモリは約 12 分で消える、Cloudflare は設定なしで成田(NRT)で動く、Supabase の Edge Function は秘密鍵を自分で扱わずに Postgres へ書ける、という「公式ページだけでは実感しにくい挙動」も確認できました

次のステップとしては、Vercel の画面に Supabase をつないで「メモリ」が「Postgres」に変わるのを見るのが、3 社の役割分担をいちばん体で覚えられる練習です。

参考リソース