The Complete Guide to Building a Multi-Tenant SaaS
Multi-tenancy lets you serve multiple customers from a single application instance. Here's how to implement it correctly from the start.
Key Takeaway
Multi-tenant architecture serves multiple customers (tenants) from one app instance. Choose shared database with tenant_id for most SaaS startups—it's simpler and cheaper. Use isolated databases only for enterprise customers with strict compliance requirements.
In This Guide
What is Multi-Tenancy?
Multi-tenancy is an architecture where a single instance of software serves multiple customers (tenants). Each tenant's data is isolated and invisible to other tenants, but they share the same application code, infrastructure, and often the same database.
Real-world example: Slack is multi-tenant. When you use Slack, you're on the same servers as millions of other workspaces. But you only see your workspace's channels and messages.
The alternative is single-tenant, where each customer gets their own dedicated instance. This is more expensive and harder to maintain, but some enterprise customers require it for compliance.
Database Design Patterns
The Organization Model
Every multi-tenant SaaS needs an organizations table. This is the top-level entity that groups users and data.
CREATE TABLE organizations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, slug TEXT UNIQUE NOT NULL, plan TEXT DEFAULT 'free', created_at TIMESTAMPTZ DEFAULT NOW() );
Linking Users to Organizations
Users can belong to multiple organizations (think: contractor working with multiple clients). Use a junction table with roles:
CREATE TABLE organization_members ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID REFERENCES organizations(id), user_id UUID REFERENCES auth.users(id), role TEXT DEFAULT 'member', -- owner, admin, member created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(organization_id, user_id) );
Tenant-Scoped Tables
Every table that contains tenant data needs an organization_id:
CREATE TABLE projects ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID REFERENCES organizations(id) NOT NULL, name TEXT NOT NULL, -- Always filter by organization_id in queries );
Implementing Data Isolation
Row Level Security (RLS)
Row Level Security is a PostgreSQL feature that automatically filters rows based on policies. Even if your application code has a bug, data can't leak to other tenants.
-- Enable RLS on the table
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
-- Create policy: users can only see their organization's projects
CREATE POLICY "Users can view own org projects"
ON projects FOR SELECT
USING (organization_id IN (
SELECT organization_id FROM organization_members
WHERE user_id = auth.uid()
));With this policy, SELECT * FROM projects automatically returns only the current user's organization's projects. No WHERE clause needed.
Application-Level Checks
RLS is your safety net, but you should also filter in your application code:
# Python/FastAPI example
async def get_projects(org_id: str, user: User):
# Verify user belongs to this organization
if org_id not in user.organization_ids:
raise HTTPException(403, "Not a member of this organization")
# Filter by organization_id
return db.query(Project).filter(
Project.organization_id == org_id
).all()How HiveForge Implements Multi-Tenancy
HiveForge uses the shared database model with Row Level Security. Here's what you get out of the box:
- Organizations table with plans and billing
- Organization members with roles (owner, admin, member)
- Invitation system for adding team members
- RLS policies on all tenant-scoped tables
- Middleware that sets the current organization context
- API routes scoped to the current organization
- Admin dashboard for managing all organizations
You don't have to implement any of this yourself. Create an account, and you have multi-tenant architecture ready to go.
Skip 3-4 Weeks of Architecture Work
HiveForge includes production-ready multi-tenant architecture. Organizations, members, roles, RLS—all done.
Get Started FreeFrequently Asked Questions
Can I offer both shared and isolated to different customers?
Yes. Start with shared for most customers, then offer isolated databases as an enterprise add-on. HiveForge supports this hybrid approach.
How do I handle per-tenant customization?
Store tenant-specific settings in an organization_settings table. For UI customization (logos, colors), store these as organization metadata.
What about performance at scale?
Shared databases scale well with proper indexing on organization_id. Slack, Notion, and most B2B SaaS use shared databases. You'll likely hit other bottlenecks first.