You want to launch and iterate fast
Your users have similar needs (same features, pricing tiers)
You're using modern frameworks with built-in tenant isolation
Schema-per-Tenant = Separate Floors in the Same Building
One database server, but each tenant gets their own schema (namespace).
How it works:
- Each tenant has tables like
tenant_123.users, tenant_123.orders
- Your app switches schemas based on who's logged in
- Better separation than row-level filtering, cheaper than separate databases
Advantages:
- Better isolation than pure multi-tenant
- Easier to backup/restore individual tenants
- Still cheaper than full single-tenant
- Can migrate specific tenants to their own database later
Disadvantages:
- More complex than simple multi-tenant
- Some ORMs don't handle this well
- Database connection pooling gets trickier
- Migration scripts need to run on all schemas
Popular tools:
-
Django: django-tenants (formerly django-tenant-schemas)
-
Node.js: Knex.js with schema switching, or Prisma with multi-schema support
-
Ruby on Rails: Apartment gem
- Postgres: Built-in schema support
Security (The Scary Part)
Multi-tenant security means more than just adding a tenant_id column.
Three Levels of Protection:
-
Database: Use row-level security or tenant views.
-
Application: Always filter queries by tenant.
-
API: Make sure tokens connect users to the right tenant.
Common mistakes:
- Forgetting
WHERE tenant_id = ? → Instant data leak
- Wrong JWT token → Can access another tenant's data
- Admin panels that bypass tenant filters → Privacy nightmare
- Sharing caches across tenants → Information disclosure
Tools That Help:
-
Supabase: Built-in RLS, auth hooks, and tenant isolation patterns
-
Prisma: Row-level security middleware and tenant filtering
-
PostgREST: API that enforces Postgres RLS automatically
-
Django Tenants: Mature library for schema-per-tenant in Django
-
PlanetScale: Database branching makes tenant testing easier
Security Best Practices:
- Use Postgres RLS as your backup layer
- Choose an ORM that enforces tenant filtering by default
- Include tenant_id in all JWT tokens
- Create separate admin roles with explicit permissions
- Test with multiple tenants in every environment
- Log all cross-tenant access attempts
- Use database-level constraints where possible
Why I chose multi-tenant
-
I'm bootstrapping. Single-tenant would be too expensive
- My users don't need custom setups.
-
I want to move fast. One update for all tenants
-
I can always switch later Big clients could get single-tenant setups.
What Should You Do?
Go multi-tenant if:
- You're bootstrapping or self-funded.
- You want to launch fast.
- Your users have similar needs.
- You don’t deal with heavy security rules.
- Infrastructure costs matter
Go Schema-per-Tenant If:
- You want better isolation than pure multi-tenant
- You plan to offer data export/backup per tenant
- You might need to migrate large clients later
- Your users have moderately different needs
- You're okay with more complex migrations
Go single-tenant if:
- You work with enterprise clients.
- You have funding for infrastructure.
- You need strict data separation.
- You offer custom setups.
- Clients demand it (and pay for it)
Final Thoughts
I spent too much time reading about this when I should have been coding.
Big SaaS companies like Notion, Vercel, Shopify, and Zoom also started simple and are still multi-tenant. Slack started multi-tenant, now hybrid.
The real problem isn’t "choosing wrong", it’s never launching at all.
Many companies eventually use both: multi-tenant for most users and single-tenant for large clients like Stripe or GitHub.
If you’re still deciding, start simple. Build, launch, and learn. You can always improve later.