Back to Home
Multi-Tenancy
Implement multi-tenant architecture with organizations, teams, and role-based access control.
PropelKit supports both single-user SaaS and team-based SaaS with a tenant context abstraction that makes your code work for both modes.
How It Works
Enable with features.multiTenancy: true.
Single-User Mode
When multiTenancy is false:
- User logs in → goes directly to dashboard
- Subscriptions tied to user account
- No team management UI
- getTenantContext() returns { type: 'user', id: userId, ownerId: userId }
Multi-Tenant Mode
When multiTenancy is true:
- User logs in → must create or join an organization
- Team invitations and member management
- Role-based permissions (Owner / Admin / Member)
- Subscriptions tied to organization
- getTenantContext() returns { type: 'organization', id: orgId, ownerId: userId, role: 'owner' }
The Tenant Context API
TypeScript
import { getTenantContext } from '@/lib/tenancy';
const tenant = await getTenantContext();
// Single-user: { type: 'user', id: '...', ownerId: '...' }
// Multi-tenant: { type: 'organization', id: '...', ownerId: '...', role: 'owner' }
// Pending: { type: 'pending', id: '...', ownerId: '...' }This single API works everywhere — API routes, server components, middleware. Your code doesn't need to know which mode is active.
Role Checks
TypeScript
import { hasRole, isOwner, isOwnerOrAdmin } from '@/lib/tenancy';
await isOwner() // true if owner
await isOwnerOrAdmin() // true if owner or admin
await hasRole('admin') // true if admin
await hasRole(['owner', 'admin']) // true if owner OR adminDatabase Tables
When multi-tenancy is enabled, three additional tables are created:
- organizations — id, name, slug, owner
- organization_members — links users to orgs with roles
- organization_invites — pending invitations with tokens and expiry