0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Supabase無料枠「2プロジェクト」を設計で乗り切る — テーブルprefixで複数サービスを1プロジェクトに相乗りさせる運用術

0
Posted at

個人開発でSupabaseを使っていると、いつかこの壁に当たります。

  • 3つ目のサービスを作ろうとしたら、無料枠の「アクティブ2プロジェクト」上限に引っかかった
  • まだ収益もユーザーもいない実験サービスのために、有料プランへ上げる決心はつかない
  • 枠を空けるために古いプロジェクトを消したいが、「本当に消して大丈夫か」が怖くて手が止まる

この記事では、筆者が実際にやっている解決策 — 1つのSupabaseプロジェクトに複数サービスを「相乗り」させ、テーブル名のprefixで名前空間を分ける運用 — を紹介します。

この記事で分かること

  • 「1サービス=1プロジェクト」をやめて相乗りさせるという発想
  • テーブルprefixによる名前空間設計の具体例
  • 相乗り運用で事故らないための4つのルール(台帳・撤退・RLS・マイグレーション)
  • PostgreSQLのschema分割との比較、相乗りのデメリットと「卒業」の判断基準

前提:Supabase無料プランは「アクティブ2プロジェクト」まで

Supabaseの無料プランには、アクティブにできるプロジェクト数の上限があります。執筆時点(2026年7月)で2プロジェクトです。

⚠️ プラン仕様は変わる可能性があります。最新の上限・条件は必ずSupabase公式のPricingページ( https://supabase.com/pricing )で確認してください。

2つと聞くと十分に思えますが、個人開発者のサービスは2個では止まりません。X自動投稿ボット、リサーチツール、ログ収集、次のアイデアの実験——「DBが欲しい小さなサービス」は増え続けます。そして3つ目を作った瞬間に詰みます。

このとき取れる選択肢は、大きく3つです。

選択肢 問題点
有料プランに上げる まだ検証段階のサービスに固定費を払うことになる
既存プロジェクトを消して枠を空ける 稼働中サービスのデータを失うリスク。撤退判断のたびにDBが人質になる
1プロジェクトに相乗りさせる 設計と運用ルールが必要(→本記事)

解決策:テーブルprefixで名前空間を分けて相乗りさせる

発想の転換はシンプルで、「1サービス=1プロジェクト」という前提を捨てることです。

Supabaseのプロジェクトの実体は1つのPostgreSQLデータベースです。個人開発の小規模サービスであれば、複数サービスのテーブルが1つのDBに同居しても構造上は何の問題もありません。問題は「どのテーブルがどのサービスのものか」が分からなくなることなので、そこを**テーブル名のprefix(接頭辞)**で解決します。

命名例

サービス prefix テーブル例
メディア自動投稿 media_ media_posts, media_post_logs
商品リサーチツール radar_ radar_products, radar_price_history
通知ボット bot_ bot_logs, bot_subscribers

命名のポイントは3つです。

  1. prefixは「サービスの実体が分かる短い英単語」にするapp1_ のような連番は半年後に読めなくなります
  2. 例外なく全テーブルに付ける。「これは共通で使うから」とprefixなしのテーブルを作ると、撤退時の棚卸しで必ず迷子になります
  3. ダッシュボードのテーブル一覧は名前順に並ぶので、prefixを揃えるだけでサービスごとに固まって表示される。これが運用上、地味に効きます

相乗り運用で事故らないための4ルール

相乗りは「入れるだけ」なら誰でもできますが、事故らずに回し続けるには運用ルールが要ります。筆者が実運用で守っているのは次の4つです。

# ルール 破るとどうなるか
1 prefix台帳を必ず残す どのテーブルがどのサービスのものか誰にも分からなくなる
2 プロジェクトごと削除は絶対にしない 同居中の稼働サービスを巻き込んで消す
3 RLSとキーの扱いをサービスごとに分けて設計する あるサービス経由で別サービスのデータに届いてしまう
4 マイグレーションもprefixごとに管理する 変更履歴がサービス横断で混ざり、追跡不能になる

ルール1:どのprefixがどのサービスか、台帳を必ず残す

READMEでもリポジトリ内のMarkdownでも構いませんが、「このプロジェクトには何と何が相乗りしていて、それぞれのprefixは何か」の対応表を必ず文書化します。

## Supabase相乗り台帳(プロジェクト: main-shared)
| prefix  | サービス           | 状態   | リポジトリ        |
|---------|--------------------|--------|-------------------|
| media_  | メディア自動投稿   | 稼働中 | infra_media_bot   |
| radar_  | 商品リサーチ       | 稼働中 | infra_radar       |
| bot_    | 通知ボット         | 撤退済 | (アーカイブ)      |

頭の中にしかない対応表は、数ヶ月後の自分には存在しないのと同じです。

ルール2:撤退してもプロジェクトは消さない。棚卸しはテーブル単位で

相乗り運用でいちばん危険な操作が「プロジェクト削除」です。あるサービスから撤退したとき、単独プロジェクトの感覚で「もう使ってないから」とプロジェクトを消すと、同居している稼働中サービスのデータごと消えます

撤退時の片付けは、必ずテーブル単位で行います。

  • 台帳でそのprefixのテーブルを洗い出す
  • 必要ならエクスポートしてから、DROP TABLE をテーブル単位で実行する
  • 台帳の状態を「撤退済」に更新する

「プロジェクト削除ボタンは押さない」を鉄の掟にしておくだけで、最悪の事故は防げます。

ルール3:anonキーは全サービス共有になる。RLSとアクセス経路を分けて考える

相乗りの技術的な急所はここです。Supabaseのanonキー(クライアント公開用キー)はプロジェクト単位なので、相乗りした全サービスで同じanonキーを共有することになります。つまり、サービスAのフロントエンドに埋めたキーは、理屈の上ではサービスBのテーブルにも届き得ます。

筆者の設計判断は次の通りです。

  • 基本はサーバーサイド経由に寄せる。クライアントからSupabaseを直接叩かず、API Route等のサーバー側からアクセスする構成にすれば、anonキー共有の問題面はかなり小さくなります。サーバー専用キーは環境変数でサーバーにのみ置きます
  • クライアント直アクセスがどうしても必要なテーブルだけ、RLSポリシーをサービス単位で明示的に書く。「RLSはprefixごとに設計する」と決めておくと、ポリシーの抜け漏れに気づきやすくなります

単独プロジェクトなら「anonキー+RLS」で素直に済む場面でも、相乗りでは「このキーは他サービスにも届く」ことを常に前提に置く必要があります。

ルール4:マイグレーションもprefixごとに管理する

マイグレーションファイルにもサービスのprefix(またはサービス名)を入れておくと、後から「このサービスのスキーマ変更履歴」だけを追えます。

migrations/
  media_001_create_posts.sql
  media_002_add_post_logs.sql
  radar_001_create_products.sql

これをやらずに時系列だけで積むと、複数サービスの変更が1本の履歴に混ざり、「radar側だけロールバックしたい」ときに泣きます。

PostgreSQLのschema分割と比べてどうか

「名前空間を分けたいならPostgreSQLのスキーマ機能(CREATE SCHEMA media;media.posts)を使うべきでは?」という意見は当然あります。比較すると次の通りです。

観点 prefix方式(public内) schema分割方式
名前空間としての厳密さ 命名規約ベース(緩い) DBレベルで分離(厳密)
Supabaseダッシュボードとの相性 デフォルト表示にそのまま載る スキーマ切替の操作が挟まる
クライアントライブラリ デフォルト(publicスキーマ)でそのまま動く 公開スキーマの追加設定やスキーマ指定が必要
導入コスト テーブル名を決めるだけ スキーマ作成・公開設定・接続側の指定

schema分割の方がデータベース設計としては「正しい」形です。ただし、Supabaseのダッシュボードやクライアントライブラリはpublicスキーマをデフォルトの前提にしているため、カスタムスキーマ運用は一手間ずつ設定が増えます。

個人開発の相乗りで欲しいのは厳密な分離ではなく「迷子にならないこと」なので、ツールのデフォルトの路線から外れないprefix方式で十分、というのが筆者の判断です。分離の厳密さが本当に必要になったときは、後述する「卒業」を検討するタイミングです。

デメリットも正直に:相乗りは「ずっと」の解ではない

相乗りには、はっきりしたデメリットがあります。

  • 容量・負荷の枠を全サービスで共有する。無料枠のDB容量や帯域は1プロジェクト分を分け合うことになり、1つのサービスが枠を食いつぶすと全員が困ります
  • 事故時の巻き込み範囲が広い。プロジェクトが止まれば相乗りしている全サービスが止まりますし、SQLの誤操作が他サービスのテーブルに及ぶ可能性も単独運用より高くなります
  • いつか分離したくなったときに移行コストがかかる。テーブルのエクスポート/インポートに加え、接続情報・キー・RLSの作り直しが必要です

だからこそ、相乗りは「検証段階のサービスを安く並走させるための設計」と割り切り、卒業の基準を決めておきます。筆者は次のどれかに当たったら、専用プロジェクト(有料プラン含む)への移行を検討することにしています。

  • 外部ユーザーが本格的に付き、止められないサービスになった
  • 1つのサービスが容量・負荷の共有枠を明らかに食い始めた
  • クライアント直アクセスが本格的に必要になり、キー共有前提のRLS設計が複雑になりすぎた

成長したサービスを卒業させれば無料枠の相乗りプロジェクトには余白が戻り、また次の実験を安く始められます。

まとめ

  • Supabase無料プランはアクティブプロジェクト数に上限がある(執筆時点で2。最新は公式Pricingページで要確認)
  • 「1サービス=1プロジェクト」を捨て、テーブルprefixで名前空間を分けて1プロジェクトに相乗りさせれば、3つ目以降のサービスも無料枠で並走できる
  • 事故防止の4ルール:①prefix台帳を残す ②プロジェクトごと削除は絶対にしない(棚卸しはテーブル単位) ③anonキー共有を前提にRLSとアクセス経路を設計する ④マイグレーションもprefixごとに管理する
  • schema分割より厳密さは劣るが、Supabaseのデフォルト(publicスキーマ)とそのまま噛み合うのがprefix方式の実利
  • 相乗りは検証段階の設計。成長したサービスは専用プロジェクトへ卒業させ、空いた枠で次の実験を回す

無料枠の上限は「制約」ですが、相乗り設計にしてからは「どのサービスを本気で育てるか」を考えるきっかけにもなっています。同じ悩みを持つ個人開発者の参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?