最近、個人開発界隈でSupabaseの人気が爆上がりしてますよね。「Firebaseより安い!」「PostgreSQLベースで最高!」みたいな声をよく聞きます。確かにSupabaseは素晴らしいBaaSなんですけど、実際に使ってみると「あれ?思ってたのと違う...」ってなることも結構あるんです。
今回は、私が実際にSupabaseでプロダクトを作って痛い目にあった経験から、皆さんが同じ轍を踏まないように気をつけるべきポイントをまとめてみました。
Row Level Security(RLS)は必須だけど、めちゃくちゃ罠が多い
Supabaseを使い始めて最初に「おお!」って感動するのが、PostgreSQLのRow Level Security(RLS)機能なんですよね。データベースレベルでアクセス制御ができるって、セキュリティ的にも最高じゃないですか。
でも、これがまた曲者でして...。
最初は「とりあえずRLSオンにしておけばいいでしょ」って軽い気持ちでやると、データが取れなくなって焦ります。私も最初、「なんでデータが空なの??」って3時間くらい悩みました。RLSをオンにすると、デフォルトでは誰もアクセスできない状態になるんですよ。
そして、ポリシーを書き始めると今度は別の罠が。例えば、「自分のデータだけ取得できる」っていうシンプルなポリシーを書いたつもりが、JOINしたときに想定外の動きをしたり、パフォーマンスが急激に悪化したり...。特に、複雑な条件を持つポリシーは要注意です。
あと、開発中はRLSオフにして作業することも多いと思うんですが、本番環境でオンにし忘れるという事故も起きがちです。私の知り合いは、これで一時的に全ユーザーのデータが丸見えになってしまい、大慌てで対応してました。
リアルタイムサブスクリプションの制限を甘く見ない
Supabaseのリアルタイム機能、めちゃくちゃ便利ですよね。データベースの変更を即座にクライアントに反映できるなんて、まるで魔法のよう。チャットアプリとか、コラボレーションツールを作るときには本当に重宝します。
ただ、無料プランだと同時接続数が200までという制限があるんです。「200もあれば十分でしょ」って思うかもしれませんが、これが意外と厳しい。
なぜかというと、ユーザーがタブを複数開いたり、モバイルアプリがバックグラウンドで接続を維持したりすると、あっという間に接続数が膨れ上がるんです。私が作ったアプリでは、アクティブユーザー50人くらいで接続数が限界に達してしまいました。
しかも、接続数が上限に達すると、新しいユーザーは接続できなくなります。エラーハンドリングをちゃんとしていないと、アプリが真っ白になったり、無限ローディングになったりして、ユーザー体験が最悪になります。
対策としては、不要なサブスクリプションはこまめに解除する、一定時間操作がなければ自動的に切断する、といった工夫が必要です。あとは、本当にリアルタイムが必要な機能なのか、ポーリングで十分じゃないか、という設計の見直しも大切ですね。
Edge Functionsのコールドスタート問題
Supabase Edge Functionsは、Deno Deployをベースにしたサーバーレス関数で、とても使いやすいです。TypeScriptがそのまま動くし、Supabaseクライアントも簡単に使えるし、最高!って思うじゃないですか。
でも、ここにも落とし穴があります。それがコールドスタート問題。
しばらくアクセスがないと、関数がスリープ状態になってしまうんです。次にリクエストが来たとき、関数を起動するのに数秒かかることがあります。ユーザーからすると「なんでこんなに遅いの?」ってなりますよね。
私の場合、決済処理をEdge Functionsで実装していたんですが、朝一番のユーザーが決済しようとすると、タイムアウトしてしまうことがありました。お金が絡む処理でこれは致命的です。
回避策としては、定期的に関数を呼び出してウォームアップしておく、クリティカルな処理は別のサービスを使う、といった対応が必要です。あとは、ユーザーに対して初回は少し時間がかかることを事前に伝えておくのも、意外と効果的だったりします。
ストレージの画像変換APIの制限
Supabase Storageには、画像をリサイズしたり、フォーマットを変換したりできる便利なAPIがあります。「?width=200&height=200」みたいなクエリパラメータを付けるだけで、サムネイルが作れるなんて最高ですよね。
でも、これにも罠があるんです。無料プランだと、画像変換の回数に制限があります。しかも、この制限がドキュメントに明記されていないことが多くて、気づいたら制限に引っかかっていた、なんてことも。
私のアプリでは、ユーザーがアップロードした画像を、一覧画面用、詳細画面用、OGP用...みたいに複数のサイズで表示していました。そうすると、1枚の画像に対して3〜4回の変換が発生します。ユーザーが増えてくると、あっという間に制限に達してしまいました。
対策としては、よく使うサイズは事前に生成してキャッシュしておく、クライアント側でリサイズしてからアップロードする、といった工夫が必要です。または、画像変換専用のサービス(CloudinaryやImgixなど)を併用するのも一つの手です。
無料プランの7日間の非アクティブ制限
これ、意外と知らない人が多いんですが、Supabaseの無料プランには「7日間アクセスがないとプロジェクトが一時停止される」という制限があります。
開発中のプロジェクトって、忙しくて1週間くらい触らないこともありますよね。そうすると、次にアクセスしたときに「あれ?データベースに繋がらない...」ってなるんです。
プロジェクトを再開するには、ダッシュボードから手動で起動する必要があります。これ自体は簡単なんですが、問題は自動化されたプロセスが止まってしまうこと。
例えば、定期的にデータを収集するcronジョブとか、外部サービスからのWebhookとか。これらが知らないうちに止まっていて、データの欠損が発生したり、ユーザーからクレームが来たり...。
対策は簡単で、GitHub ActionsなりVercelのcron機能なりを使って、定期的にデータベースにアクセスするようにしておけばOKです。私は毎日午前9時に、ヘルスチェック用のAPIを叩くようにしています。
まとめ
Supabaseは本当に素晴らしいサービスです。個人開発者にとって、これほど使いやすくて高機能なBaaSは他にないと思います。ただ、完璧なサービスなんてこの世には存在しません。
大切なのは、サービスの特性や制限を理解した上で、適切に使うこと。そして、問題が起きたときに慌てないよう、事前に対策を考えておくことです。
この記事で紹介した内容は、私が実際に経験した「痛み」から学んだものです。皆さんが同じ失敗をしないよう、少しでも参考になれば嬉しいです。
Supabaseと上手く付き合って、素晴らしいプロダクトを作っていきましょう!