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 層でできていて、各社が自前で持っている層が違います。

図1:Vercel は画面と API、Cloudflare は 3 層すべて、Supabase は API と保存を持つ。「Vercel + Supabase」は公式ドキュメントが想定する定番の組み合わせ
先に結論
結論から書きます。評価の観点は「公開のしやすさ」「無料で続けられるか」「AI ツールから操作できるか」の 3 つです。

図9:AI ツールからの操作(MCP)は 3 社とも ChatGPT・Claude の公式一覧に載っていて差がつかない。差がつくのは「無料で商用できるか」と「DB が付いているか」
| 観点 | Vercel | Cloudflare Workers | Supabase |
|---|---|---|---|
| 役割 | 画面と 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 / R2 | Postgres が本体 |
| 東京で動く | 関数リージョン 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 の料金ページ(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 つ | 全リージョン |
| Cron | 1 日 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 の料金表(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 / R2 | KV 1GB、R2 10GB | 従量 | 従量 |
| Git 連携ビルド | 3,000 分/月 | 6,000 分/月 | 同左 |
| ログ保持 | 3 日 | 7 日 | Logpush |
| Workers AI | 1 万 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 の料金ページ(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 Functions | 50 万回 | 200 万回、+$2/100 万回 | 同左 | カスタム |
| 帯域(egress) | 5GB | 250GB、+$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 社で並べました。どれも「お金が勝手に請求される」のではなく、「止まる」「できない」の形で現れます。

図8:赤字が「止まる・できない」、緑字が「無料でも十分」。下段は最初の有料プランで何が変わるか
どれを選ぶか:判断フロー

図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 付きの SPA | Cloudflare Workers | Worker 1 本で API、D1 で保存。Free でも 10 万回/日 |
| ログインが要る、ユーザーごとのデータがある | Supabase + 画面は上のどちらか | Auth と Postgres と RLS が揃う。Free で MAU 5 万 |
| 収益化する(広告・課金) | Cloudflare Free か Vercel Pro | Vercel Hobby は商用不可。Cloudflare は Free でも可(カード情報は Stripe などへ) |
| 公開デモを放置する | Cloudflare か Vercel | Supabase Free は 1 週間でプロジェクトが止まる |
| 長い処理(数分の AI 生成) | Vercel Pro(800 秒)か Cloudflare Paid(CPU 5 分) | Free は Vercel 300 秒、Cloudflare CPU 10ms |
検証:同じアプリを 3 社に載せる
ここからは実際に手を動かします。検証用に「ひとことボード」という小さなアプリを用意しました。入力欄に一言を書いて投稿すると一覧に並ぶ、掲示板の最小形です。画面は 3 ファイル(HTML・JS・CSS)だけで、フレームワークは使っていません。

図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"]
}
手順は次のとおりです。

図4:push から本番 URL まで約 1 分。URL と応答コードは実測
- GitHub にリポジトリを作って push します。
# 検証アプリのフォルダで実行。非公開リポジトリを作って push する
gh repo create Takuya-ops/hitokoto-board --private --source=. --remote=origin --push
- vercel.com/new を開き、リポジトリ一覧から
hitokoto-boardの Import を押します。Vercel の GitHub アプリが入っていれば一覧に出ます。 - Root Directory を
vercel/にします。1 リポジトリに 3 構成を入れたためです。Framework Preset は「Other」のままで構いません。

Root Directory を vercel にしたところ。プロジェクト名は自動で hitokoto-board-vercel になった
- Deploy を押します。ビルドは 11 秒、画面が切り替わるまで約 1 分でした。

デプロイ完了画面。下には「Turn Your Agent into a Vercel Expert」として Vercel プラグインの導入コマンドが出る
- 本番 URL を開いて投稿してみます。画面の「配置先」が
Vercel Functions / hnd1(メモリ(非永続))になり、東京リージョンで動いたことが分かります。

本番 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":[]}

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)
},
};

図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"}]}

ローカル実行。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 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":[]}

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

本番 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 ヘッダーは省略
});

図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."}

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

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、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 キーを手で貼る必要はありません。

図7:つなぎ方は 3 社とも同じ。違うのは「つないだ先で何ができるか」と「権限の絞り方」
Claude.ai と ChatGPT の両方で、実際に一覧を検索して掲載を確認しました。

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

ChatGPT の「カスタマイズ > プラグイン」。Cloudflare は「Manage Cloudflare resources」と「platform guidance with official MCP」の 2 種が公式
| サービス | サーバー URL | Claude.ai / Desktop | ChatGPT | Claude Code | Codex CLI |
|---|---|---|---|---|---|
| Vercel | https://mcp.vercel.com | 一覧に「Vercel」 | 一覧に「Vercel」 | claude mcp add --transport http vercel https://mcp.vercel.com | codex mcp add vercel --url https://mcp.vercel.com |
| Supabase | https://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" |
| Cloudflare | https://bindings.mcp.cloudflare.com/mcp ほか 17 種 | 一覧に「Cloudflare Developer Platform」(23 ツール) | 一覧に「Cloudflare」 | /plugin marketplace add cloudflare/skills → /plugin install cloudflare@cloudflare | codex 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 の関数が遅い | 既定リージョンが米国 iad1 | vercel.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 社の役割分担をいちばん体で覚えられる練習です。
参考リソース
- Vercel:Pricing / Hobby plan / Fair Use Guidelines / Deployment Protection / Marketplace storage / Vercel MCP
- Cloudflare:Workers Pricing / Limits / Static Assets / D1 Pricing / MCP servers for Cloudflare / Self-Serve Subscription Agreement
- Supabase:Pricing / Free project pausing / Edge Functions Limits / Row Level Security / Supabase MCP / Vercel Marketplace integration
- Anthropic / OpenAI:Claude Code MCP / Custom connectors(Claude) / ChatGPT Developer mode / Codex MCP

