27
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

マルチテナント作るならPostgres一択。アプリ層に依存しない「RLS」によるデータ隔離が最強すぎる話

27
Posted at

はじめに

複数ユーザー(複数企業)のデータを 1 つのアプリケーションで扱う場合、マルチテナントという考え方がとても便利です。

ただ、マルチテナントを採用する際に必ず悩むのが DB 設計

  • テナントごとに DB を分けるべきか
  • 1 つの DB にまとめるべきか
  • どの DB を採用すべきか

結論から言うと、私はPostgreSQL一択だと思っています。
理由はシンプルで、RLS(Row Level Security)が強すぎるからです。

マルチテナントとは?

マルチテナントとは、1 つのアプリケーションで複数の顧客(企業)を扱う設計のこと。
このとき重要なのは「絶対に他ユーザーのデータが混ざらないこと」です。
特にBtoBサービスにおいては、他社のデータが混ざる・見えることは「」を意味します。

PostgreSQL を選ぶべき最大の理由:RLS(Row Level Security)

💡 RLS とは?
RLS は PostgreSQL が持つ行レベルのアクセス制御機能です。

「このユーザーは、この行しか読めない・書けない」を DB が強制する 仕組みです。

アプリ側が気を利かせて WHERE tenant_id = X を付けるのではなく、DB 自体が “他社データを絶対に返さない” ようにする。これが本当に強いです。

RLS がマルチテナントと相性抜群な理由

① DB が強制するので「バグっても漏れない」
アプリ側で WHERE を付け忘れる事故はよくある話です。
RLS を使えば、すべてに対して DB が強制的にフィルタリングします。
アプリのバグで他社データが漏れるリスクが激減します。

② 1 つの DB に全社データを入れても安全
RLS があるので、1 つの DB に全テナントのデータを入れても絶対に混ざらない。
SaaS ではこの構成が最も一般的です。

③ Rails の acts_as_tenant などと併用できる
Rails の acts_as_tenant のように、
アプリ側で WHERE tenant_id = X を自動付与する仕組みも便利です。

ただしこれは アプリ層の工夫。
RLS は DB 層の強制。
両方使うとさらに安全になります。

アプリ層での工夫で言えば、ORMも強力です。
Next.js等の場合、Railsと違って主要ORMでは標準機能としては持っていないことが多いです。

そのため、以下のような手法で「後天的に」仕組みを組み込む必要があります。

Prisma の場合:Client Extensions
Prismaには「Client Extensions」という機能があり、これを使うと findMany などのメソッドをラップして、自動でフィルタを追加するカスタムクライアントを作れます。

イメージ: prisma.$extends(...) を使って、全てのクエリに tenantId を強制する「自分専用のPrisma」を定義する。

Drizzle ORM の場合:ラッパー関数
Drizzleは「素のSQLに近い」ことを重視しているため、自動でWHERE句を付ける魔法は今のところ公式にはありません。

対策: db.select().from(table) を直接呼ぶのではなく、withTenant(db).select().from(table) のように、必ずテナント情報を噛ませるカスタム関数を自作して運用するのが一般的です。

対比:SQLite を使う場合の問題点

SQLite は軽量で便利ですが、マルチテナントを採用する場合はかなり厳しいです。
SQLiteでマルチテナントを実現しようとした場合、「1テナント=1ファイル(DB)」にするのが理想です。ただこれを実現しようとすると「動的なマイグレーション」を自前で実装する必要があります。
よって、SQLite は「単一ユーザー」「ローカルアプリ」向けであり、マルチテナント SaaS には不向きです。

🧩 PostgreSQL の選択肢一覧

  • Neon
    →ブランチ機能が優秀、serverless
  • Supabase
    →BaaS
  • RDS / Aurora PostgreSQL
    →企業向け
  • Cloud SQL PostgreSQL
    →GCP統合・BigQuery連携

🧩 SQLite の選択肢一覧

  • SQLite
    →超軽量
  • Turso
    →SQLiteをベースにした分散エッジDB、超高速
  • LibSQL
    →クラウド向け

結論:マルチテナントを採用するなら PostgreSQL 一択

理由は以下です。

  • RLS が強すぎる
  • DB が強制的にデータ分離してくれる
  • アプリのバグで漏れない
  • 1 つの DB に全社データを入れても安全
  • SaaS の実績が圧倒的に多い

SQLite でマルチテナントをやろうとすると、DB作成・動的なマイグレーション・権限管理をすべて自前で実装する必要があり、相当重いと思います。

一方でPostgreSQL は最初から “マルチテナントを安全に実現するための機能” を持っているので、私は、マルチテナントを採用するなら PostgreSQL 一択だと考えています。

ぜひマルチテナントを採用したアプリを開発する際には上記の考え方を参考にしていただけますと幸いです!💯

27
23
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
27
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?