この記事は人間が監修し、AIに書かせました。
⓪ tldr
Cloudflare WorkersからSupabaseに繋ぐならHyperdrive経由が公式推奨。接続プーリング、IPレンジ固定化、クエリキャッシュが全部タダで付いてくる。
| 構成 | IP制限 | プーリング | ORM | コスト | 推奨度 |
|---|---|---|---|---|---|
| Workers → Hyperdrive → Direct (5432) | ⚠️ CF IPレンジで可 | ✅ CF側 | ✅ Drizzle可 | 5/月 | ✅ 推奨 |
| Workers → Supavisor (6543) | ❌ 不可 | ✅ SB側 | ⚠️ prepare:false必須 | $0 | △ 代替 |
| Workers → Data API (supabase-js) | ➖ HTTP | ➖ 不要 | ❌ ORM不可 | $0 | △ 用途限定 |
| Workers → D1 | ➖ 内部 | ➖ 不要 | ✅ Drizzle可 | $0 | ✅ CF完結向き |
最小構成のコスト感:
| 項目 | Free | Paid ($5/月) |
|---|---|---|
| Workers リクエスト | 10万/日 | 1,000万/月 |
| Hyperdrive クエリ | 10万/日 | 無制限 |
| Supabase (Free) | 500MB, 60接続 | — |
| 合計 | $0/月 | $5/月 |
DAU 1,000人規模の個人開発なら $5/月 で安全に運用できる。
先制チェック — 始める前に知っておくべき3つの内容
🚨 致命的欠落
prepare: falseを設定しないと全クエリが死ぬ — Hyperdrive/Supavisorはtransaction modeで動作する。prepared statementsは非対応。Drizzleで忘れるとError: prepared statement "s1" already existsで全滅する。- DBクライアントをグローバルスコープで初期化すると本番で死ぬ — Workersはリクエスト間でグローバル変数を共有する。前のリクエストの古い接続を掴んで
Connection terminated unexpectedlyが間欠的に発生する。 - Hyperdrive + Supavisor を重ねると壊れる — 両方ともtransaction modeプーラー。二重にするとprepared statementsの不整合やレイテンシ加算が起きる。HyperdriveにはDirect接続(5432)を渡す。
🏭 業界の常識
- SupabaseのDirect接続はデフォルトIPv6 — 2024年1月以降移行済み。Hyperdriveは内部でIPv6対応しているので基本問題ないが、IPv4アドオン($4/月)が必要になるケースもある。
- supabase-jsとDrizzle+postgres.jsは全く別の接続経路 — supabase-jsはHTTP(PostgREST経由)、Drizzle+postgres.jsはTCP(PostgreSQLワイヤープロトコル)。セキュリティモデルも制約も違うのに、混同されやすい。
- HyperdriveのDBへの送信元はCloudflareの公開IPレンジ — 公式FAQに明記されている。SupabaseのNetwork RestrictionsでこのIPレンジをallowlistに設定すれば、フルオープンを避けられる。
💣 後から気がつくと困るもの
- Hyperdrive Free: 10万クエリ/日 — 認証チェック等でリクエストごとに2〜3クエリ走ると、PV 5万/日で上限突破。Workers Paid ($5/月)にすれば無制限。
- Supabase Free: 同時接続60本 — Hyperdriveプール上限(Free: ~20, Paid: ~100)との組み合わせに注意。Freeプラン同士なら安全圏。
- Hyperdriveのクエリキャッシュはデフォルトで60秒ON — ユーザー固有データが古いまま返る可能性がある。認証系テーブルはキャッシュ無効化が必要。
① 用語解説 — 2歩手前から
接続方式を「道路」に例える
比較表
| 特性 | Hyperdrive経由 | Supavisor経由 | Data API |
|---|---|---|---|
| プロトコル | TCP (Postgres) | TCP (Postgres) | HTTP (REST) |
| ポート | — (自動) | 6543 | 443 |
| プーリング | あり (CF側) | あり (SB側) | 不要 |
| IP制限 | ⚠️ CF IPレンジ | ❌ 不可 | ➖ HTTP |
| ORM (Drizzle) | ✅ | ⚠️ prepare:false | ❌ |
| RLS | 任意 | 任意 | ✅ 前提 |
| レイテンシ | 低い(プール済み) | 中間 | 中間 |
| CF公式推奨 | ✅ | — | — |
よくある誤解を先に潰す
誤解1: 「WorkersからPostgreSQLに直接繋げない」
→ 昔は本当だったが、今はTCPソケット対応済み。さらにHyperdriveでプーリングまで面倒見てくれる。
誤解2: 「supabase-jsを使えば全部解決」
→ クライアントサイド向けの設計で、ORM非対応・型安全性が低い・トランザクション不可。サーバーサイドではDrizzle + postgres.jsの方が適している。
誤解3: 「PostgreSQLを使いたいならD1に移行するしかない」
→ D1はSQLite。PostgreSQLの機能(RLS, CTE, JSONB, pg拡張)が必要ならHyperdrive経由でSupabase/Neon等に繋ぐのが正攻法。
② Step by Step — Hyperdrive × Supabase × Drizzle の構築
なぜこの構成なのか
Cloudflare公式ドキュメントが「SupabaseにWorkersから繋ぐならHyperdrive経由」と明示している。理由は3つ:
- 接続プーリング — リクエストごとのTCPハンドシェイク(7往復)を省略
- IPレンジの固定化 — CloudflareのIPレンジから送信。allowlist設定が可能に
- クエリキャッシュ — 同じSELECTを60秒キャッシュしてDB負荷軽減
Step 1: Supabase側の準備
Supabase Dashboard → Project Settings → Database で接続情報を確認:
Step 2: Hyperdrive コンフィグ作成
もしエラーが出たら:
対処: Supabase Dashboard → Add-ons → IPv4 add-on を有効化($4/月)。SupabaseのDirect接続はIPv6がデフォルトなので、IPv4アドオンで解決する。
Step 3: wrangler.jsonc の設定
Step 4: Worker コード(Hono + Drizzle)
🪤 NG vs ✅ 正解の対比
③ 罠カタログ
罠1: prepare: false 忘れ
原因: transaction modeではクエリごとに別の物理接続が割り当てられる可能性がある。prepared statementsはコネクションに紐づくので衝突する。
エラー:
対処:
罠2: トランザクション内で外部API呼び出し
原因: transaction modeではトランザクション中ずっとDB接続を占有。外部API(3秒)を挟むとプールの1本が無駄に使われる。
エラー(接続枯渇時):
対処:
罠3: Hyperdriveキャッシュでデータが古い
原因: デフォルトで全SELECTが60秒キャッシュされる。プロフィール更新直後に古いデータが返る。
対処:
認証系などリアルタイム性が必要なデータ用に、キャッシュ無効のHyperdriveを別途作る:
罠4: Workers の同時外部接続上限
原因: Workersは1リクエストあたり同時6本まで。max: 10 は失敗する。
エラー:
対処:
罠5: nodejs_compat 未設定
原因: postgres.jsがNode.jsの crypto, net, tls を使う。フラグなしだと起動すらしない。
エラー:
対処:
④ 判断基準 — いつ何を選ぶか
フローチャート
規模別の推奨構成
| 規模 | DAU | 構成 | 月額目安 |
|---|---|---|---|
| 趣味・MVP | 〜100 | Workers Free + Hyperdrive Free + Supabase Free | $0 |
| 個人開発 | 100〜1,000 | Workers Paid + Hyperdrive + Supabase Free | $5 |
| 成長期 | 1,000〜10,000 | Workers Paid + Hyperdrive + Supabase Pro | $30 |
| B2B SaaS | 10,000+ | Workers Paid + Hyperdrive + Supabase Team | $599+ |
⑤ 内部動作 — Hyperdriveの中で何が起きているか
接続フローの比較
Hyperdriveのプーリングモード
IPレンジの仕組み
Cloudflare公式FAQより:
Hyperdrive connects to your database using Cloudflare's IP address ranges.
You can use this to configure restrictions in your database firewall.
Supabase側の設定: Dashboard → Project Settings → Database → Network Restrictions で、CloudflareのIPレンジをallowlistに追加。
⑥ 構成の選択肢と比較
Supabase vs Neon(Workers接続観点)
| 観点 | Supabase | Neon |
|---|---|---|
| 東京リージョン | ✅ あり | ❌ なし(2026/3時点) |
| Workers接続 | Hyperdrive推奨 | @neondatabase/serverless (HTTP) |
| RLS | ✅ 標準搭載 | なし(アプリ側実装) |
| 無料枠 | 500MB, 60接続 | 0.5GB, 無制限コンピュート |
東京リージョンが必要ならSupabase。不要ならNeonのHTTP driverも良い選択肢。
Supabase vs D1(Workers接続観点)
| 観点 | Supabase (PostgreSQL) | D1 (SQLite) |
|---|---|---|
| 容量上限 | プラン依存(Free: 500MB) | 10GB/DB |
| RLS / CTE / JSONB | ✅ | ❌ or 限定的 |
| pg拡張(pgvector等) | ✅ | ❌ |
| 書き込み性能 | 高い | 低い(単一ライター) |
| 移行の自由度 | 高い(他のPG環境へ移行容易) | 低い(SQLite固有) |
DBはアプリより寿命が長い。 PostgreSQLで始めれば、将来Supabaseを卒業しても他のPostgresホスティングにスキーマごと移行できる。
Drizzle + postgres.js vs supabase-js
| 観点 | Drizzle + postgres.js | supabase-js |
|---|---|---|
| 接続 | TCP (PostgreSQLプロトコル) | HTTP (PostgREST) |
| 型安全性 | ✅ スキーマから型生成 | ⚠️ 手動型定義 |
| JOIN / トランザクション | ✅ | ❌ or 制限あり |
| マイグレーション | ✅ drizzle-kit | ❌ |
| Hyperdrive互換 | ✅ | ❌(HTTP接続なので対象外) |
サーバーサイドで使うなら Drizzle。クライアントサイド(ブラウザ/React Native)ならsupabase-js。
⑦ 罠チートシート
| # | 罠名 | 影響度 | 発見タイミング | 対処 |
|---|---|---|---|---|
| 1 | prepare: false 忘れ | 🔴 全クエリ死亡 | 初回デプロイ | postgres()にprepare: false |
| 2 | グローバルDB初期化 | 🔴 間欠エラー | 負荷上昇時 | ハンドラ内で初期化 |
| 3 | nodejs_compat 未設定 | 🔴 起動不可 | デプロイ時 | wrangler.jsonc に追加 |
| 4 | Hyperdrive + Supavisor 二重 | 🔴 接続不安定 | 初回接続 | Direct (5432) を使う |
| 5 | max 値が大きすぎる | 🟡 接続枯渇 | 高負荷時 | max: 1 |
| 6 | トランザクション内で外部API | 🟡 プール枯渇 | 高負荷時 | トランザクション外に移動 |
| 7 | キャッシュでデータが古い | 🟡 体験劣化 | 更新直後 | 認証系はキャッシュ無効 |
| 8 | IPv6でcode:2015 | 🟡 セットアップ失敗 | Hyperdrive作成時 | IPv4アドオン($4/月) |
| 9 | compatibility_date が古い | 🟡 互換性問題 | 不定期 | 2024-09-23以降 |
| 10 | postgresユーザーで直接接続 | 🟡 セキュリティ | — | 専用ユーザー作成 |
⑧ 「知らなかったでは済まない」補足
Placement Hints でレイテンシ最小化
Cloudflare FAQによると、Placement設定によりクエリレイテンシが 20-30ms → 1-3ms に改善されるケースがある。Supabaseの東京リージョンと合わせると、エッジ実行でありながらDB近接配置になる。
Better Auth との組み合わせ注意
Better Authを使う場合、Hyperdrive経由で認証が不安定になる既知の問題がある(GitHub Issue #2274)。回避策:
- 認証系のみSupavisor (6543)、業務クエリはHyperdrive — 2つの接続先を使い分ける
- セッションストレージをKV/D1に逃がす — DB接続を認証から切り離す
- 最新バージョンで修正されている可能性もあるため、
signIn → session取得 → signOutの最小検証を推奨
Supabase側のNetwork Restrictions設定
Hyperdrive経由でCF IPレンジに限定する手順:
- からIPv4/IPv6レンジを取得
- Supabase Dashboard → Project Settings → Database → Network Restrictions
- CF IPレンジを追加 + 自分の開発環境IPも追加(忘れるとローカル開発で繋がらなくなる)
注意: Network RestrictionsはDirect接続とPooler接続の両方に適用される。ローカルからSupavisor経由で繋ぐ場合も自分のIPが必要。
参考資料
- Cloudflare: Connect to Supabase from Workers
- Cloudflare: Hyperdrive × Supabase
- Cloudflare: How Hyperdrive Works
- Cloudflare: Hyperdrive Pricing
- Cloudflare: Hyperdrive Limits
- Cloudflare: Hyperdrive FAQ
- Cloudflare: Workers Placement
- Cloudflare IP Ranges
- Supabase: Network Restrictions
- Supabase: IPv4 Add-on
- Supabase: Supavisor FAQ
- Supabase: Cloudflare Workers Integration