Home/ Docs/ Multi-Tenancy

Multi-Tenancy & Team Management

Workspace isolation, PostgreSQL Row Level Security, team invitations, and role-based access control for B2B SaaS applications.

Updated Apr 2026
10 min read

What's Included

The LaunchSaaS multi-tenancy package handles the organizational layer of a B2B SaaS application. Each customer account is a workspace — an isolated container for that organization's data, users, and settings.

How Data Isolation Works

LaunchSaaS uses PostgreSQL Row Level Security (RLS) to enforce tenant isolation. This is the most secure approach because it is enforced at the database level — even application-layer bugs cannot cause data leakage between tenants.

How RLS policies work

Every table that stores workspace-scoped data has a workspace_id column and RLS policies like this:

-- Only allow access to rows in the user's workspace
CREATE POLICY workspace_isolation ON workspace_resources
  USING (
    workspace_id IN (
      SELECT workspace_id FROM workspace_members
      WHERE user_id = auth.uid()
    )
  );

When a user's request hits Supabase, Postgres evaluates this policy on every query. Rows belonging to other workspaces are simply not returned — they do not appear in results and cannot be modified.

The workspace_members table

The central relationship is the workspace_members table, which maps users to workspaces with their role:

workspace_members
├── id (uuid)
├── workspace_id (uuid, FK → workspaces)
├── user_id (uuid, FK → auth.users)
├── role (enum: admin | member | viewer)
└── created_at (timestamptz)

RLS policies on all other tables reference this table to determine access.

Roles and Permissions

Action Admin Member Viewer
View workspace resources
Create & edit resources
Delete resources
Invite team members
Remove team members
Change member roles
Manage billing
Update workspace settings
Delete workspace

Role checks are enforced in two places: the UI (buttons are hidden or disabled based on role) and the API layer via a requireRole() utility that returns a 403 if the user lacks the required role. RLS policies additionally enforce admin-only data access at the database level.

Team Invitations

Workspace admins can invite new team members by email address. The invitation flow:

  1. Admin enters an email address and selects a role in the workspace settings.
  2. LaunchSaaS creates a pending invitation record in the workspace_invitations table.
  3. An invitation email is sent via Resend with a unique invite link.
  4. If the invitee has an account, clicking the link adds them to the workspace immediately.
  5. If the invitee is new, they are prompted to sign up. After signup, the invitation is applied automatically.
  6. Invitations expire after 7 days (configurable). Admins can resend or cancel pending invitations.

Extending with Custom Roles

The three built-in roles cover most B2B SaaS use cases, but you can add custom roles if needed.

Adding a "billing_manager" role

  1. Database migration: Add the new value to the role enum.
    ALTER TYPE workspace_role ADD VALUE 'billing_manager';
  2. Update TypeScript types in types/database.ts:
    export type WorkspaceRole = 'admin' | 'member' | 'viewer' | 'billing_manager';
  3. Add permissions in lib/auth/roles.ts:
    case 'billing_manager':
      return ['view_resources', 'manage_billing'];
  4. Update RLS policies if the new role needs different database access than existing roles.

Frequently Asked Questions

Does LaunchSaaS support B2B multi-tenant SaaS with team workspaces?

Yes. LaunchSaaS includes a complete multi-tenancy package designed for B2B SaaS. Each customer organization gets a workspace with isolated data, team member management, and role-based access control. A user can be a member of multiple workspaces with different roles in each.

How does LaunchSaaS handle data isolation between tenants?

Data isolation is enforced at the PostgreSQL level using Row Level Security (RLS) policies. Every tenant-scoped table has policies that only allow access to rows where the workspace_id matches a workspace the authenticated user belongs to. Even a bug in the application layer cannot accidentally return one tenant's data to another tenant.

What roles are available in LaunchSaaS RBAC and what can each role do?

LaunchSaaS includes three roles: admin, member, and viewer. Admins can manage team members, update billing, change workspace settings, and perform all member/viewer actions. Members can create and edit workspace resources. Viewers have read-only access. Role checks are enforced at both the UI and RLS levels.

How does team invitation work in LaunchSaaS — can I invite someone who doesn't have an account yet?

Yes. Team invitations work for both existing and new users. When you invite someone by email, LaunchSaaS creates a pending invitation and sends an invitation email. If the invitee is new, they are prompted to sign up first, then the invitation is automatically applied. Invitations expire after 7 days by default.

Can a single user belong to multiple workspaces in LaunchSaaS?

Yes. A single user can be a member of multiple workspaces with different roles in each. The active workspace is stored in the user's session and can be switched from the workspace selector. All workspace-scoped queries automatically use the active workspace ID.

How do I add a custom role beyond admin, member, and viewer in LaunchSaaS?

Roles are stored as a database enum and checked via lib/auth/roles.ts. To add a custom role: add the value to the enum in a migration, update the TypeScript type, add the new role's permissions to hasPermission(), and update any RLS policies that need different data access for the new role.

Ready to ship

Skip the boilerplate. Ship your product.

14 production packages. 2,335 tests. Battle-tested by 13,000+ users. One-time payment. Lifetime access.

Get Instant Access — $99