
Designing Low-Latency, Multi-Tenant Data Schemas for B2B Platforms on Supabase and PostgreSQL
Every B2B SaaS platform eventually has to answer the same question: how do you isolate one customer's data from another's while sharing infrastructure to keep costs sane? For FirmFlow AI, this wasn't a scaling problem we deferred law firm data (case files, client records, invoices) has confidentiality obligations from day one, so the schema had to get this right before the first beta user signed up.
Row-Level Security as the tenancy boundary, not application code
We use Supabase (PostgreSQL) with Row-Level Security (RLS) policies as the actual enforcement boundary for tenant isolation not application-layer WHERE firm_id = ? checks scattered across API routes. Every table that holds firm-scoped data (cases, clients, documents, invoices, staff) carries a firm_id column, and RLS policies deny any query that doesn't match the authenticated user's firm enforced at the database, so a bug in application code can't leak another firm's data.
Why this matters for latency, not just security
The naive multi-tenant pattern a separate schema or database per tenant gives you clean isolation but kills connection pooling and makes cross-tenant analytics (the kind used in FirmFlow's firm-wide dashboard) expensive. A shared-schema, RLS-enforced model keeps a single connection pool warm across all tenants, and PostgreSQL's query planner uses the same indexes regardless of which firm is querying.
