Supabaseを初めて触る人がNext.jsで開発するときに知っておきたいこと
2025年3月28日(金)に Xserver VPS で Supabase が使えるようになりました。
これを機会にSupabaseに触れる人も増えるかと思いますので、Next.js + Supabase で初めて開発する際に知っておきたい情報をご紹介します。
1. RLSという概念がある
SupabaseはデータベースとしてPostgreSQLが使われています。PostgreSQLにはRLSという機能があります。RLSとは、行単位でのアクセス権限を制御するものです。
ユーザー投稿型のサービスを例に見てみましょう。
投稿は投稿者自身だけが編集・削除したいですよね。外部の人間には編集・削除されたくありません。
そんなときに使えるのがRLSです。「user_id」というカラムを用意してユーザーIDを入れておけば、RLSで SELECT / UPDATE / DELETE に対して user_id = auth.uid()
と指定するだけで、ユーザー自身だけが編集・削除ができるようになります。
編集・削除に関する制御をアプリケーション層で何も実装しなくても安全性が担保されることになります。めちゃくちゃすごい!
2. フロントエンド側から直接DBを操作できるけど使いどころが結構限られる
Supabaseではサーバーサイドを通さずにフロントエンドから直接DBを操作できます。「フロントエンドから直接DB操作できて便利じゃん!」はその通りなのですが、ユーザー交流型のサービスには適さないため、サーバーサイドを通した実装をオススメします。
というのも、何らかの一覧ページを作るときは基本的に RLS で全てのリクエストを true
にすることになってしまいます。これが結構大きな問題で、headers情報を添えた状態でエンドポイントを変更すれば自由な条件でDBを検索できてしまうのです。
▼ 過去、既に3万以上のユーザーを獲得していた実際のサービスでDBが丸見えになるインシデントを発見して報告したことがあります。フロントエンドから取得 + RLSの設定ミス が原因で外部から丸見えになっていた事件です。
今のところ僕の考えとしては フロントエンドから直接DB操作するのは使いどころをしっかり見極める必要がある です。
具体的には、
- ユーザーのダッシュボードで操作する箇所に限り RLS でユーザー自身のCRUD権限
user_id = auth.uid()
とした場合にはフロントエンドから直接取得してもOK。 - 一般公開するような一覧ページに出力するデータはフロントエンドからの直接取得はやめておくべき。実装する際はAPI Routesを通してデータ取得する。どうしてもフロントエンドだけで実装したい場合は
.rpc()
で取得する。
というような使い分けです。
データ管理周りの操作として使う程度に抑えておくと良いでしょう!
service_role
で実行すればOK
3. API Routesでデータ操作したいときは Supabaseには様々なキーがあり使い分けが難しく感じるかと思いますが意外と単純です。
キーの名称 | 役割 |
---|---|
anon key | フロントエンド側から操作するときに使う。フロント側に露出しても問題なし。 |
service_role key | サーバーサイドで操作するときに使う。絶対に露出しちゃダメ。シークレットキーに相当する。 |
service_role key
を使うときは下記のようにします。
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(supabase_url, service_role_key, {
auth: {
autoRefreshToken: false,
persistSession: false
}
});
await supabase.from(`hoge`).select(`*`);
service_roleを通すことで、RLSの Target Roles
の service_role
に限定したリクエストを通すことができます。
これによって service_role key を知らない人からのリクエストを一切受け付けない動きを実現できます。サーバーサイドからのリクエストを管理者権限相当にできる従来のサーバーサイド + DB のような関係性を作れます。
また、普通に supabase-js
が使えますから、特別なORMなしで気軽に実装できますね!
4. ローカル環境のSupabaseは重いので物理的にマシンを分けるとすごく快適!
Supabaseはオープンソースなのでローカル環境での開発にも対応しています。
ですが、かなり重いので嫌悪感を持っている方も多いのではないでしょうか。そこで提案したいのが物理的なマシンを分けてしまう方法です。これは僕も実際に使っています!
物理的なマシンを分けた状態でリバースプロキシを立てておけば、1台のマシンで動いているのとほとんど変わらない開発体験を保つことができます。
具体的な方法は下記にまとめてありますのでご覧ください。
5. ローカル環境でOAuth処理するときは調整が必要!
OAuth処理をローカル環境で実装すると、 http://localhost:3000/ で閲覧していたはずが、 http://127.0.0.1:3000/ に飛ばされてしまう問題に遭遇しました。公式ドキュメントにも特に言及されておらず、問題解決に時間を要しました。恐らくほとんどの方が遭遇する問題かと思いますので、参考記事を下記に掲載しておきます。
6. コストを下げたいなら storage 機能は使わない方がいいかも!
Supabaseを無料枠で抑えたいなら straoge は極力使わない方がいいと思います。
「5GB bandwidth」という制限があります。
これは下り方向(エグレス)のコストがカウントされます。データ転送量が5GBを超えると有料枠となります。画像や動画などの大きなサイズになりがちなデータをSupabaseから配信してしまうと、5GBはあっという間に超えてしまいます。
その対策として画像や動画は Cloudflare R2 や GCPの Cloud Storage にアップロードして回避するのをオススメします!
おしまい
これらの情報はSupabaseに対するハードルを下げてくれるかと思います。僕もSupabaseの情報・ノウハウが知りたいので、これらの情報が誰かの助けになり、より良い情報がZennに溢れてくれることを願っています!
主に Supabaseの中の人(DevRel のタイラーさん)のポストをまとめた Supabase の細かい情報を下記にもまとめてありますのでぜひご覧ください。
Discussion