projects table scoped to the active organization, with admins allowed to delete and members only to read and edit.
You’ll use: Organizations, Invitations, access rules, named rules.
Before you start: do An app with signed-in users or be comfortable with sign-in and table rules.
How it works
Every session acts in one organization at a time. The access token carries it, and your rules read it:
Each team table has an
org column. The rule compares $record.org with $auth.org. Switching organization refreshes the token, and every rule follows.
1. Create the table
Data → Tables → Create tableprojects:
2. Write the rules once, as named rules
Open Policies → New policy and create three named rules:team_member: someone in the record’s organization.
- All of these rules pass:
- Check a value:
$auth.orgis set - Compare values:
$record.orgequals$auth.org
- Check a value:
team_create: creating a record in your own organization.
- All of these rules pass:
- Check a value:
$auth.orgis set - Compare values:
$input.orgequals$auth.org
- Check a value:
team_admin: an admin or owner of the record’s organization.
- All of these rules pass:
- Check a value:
$auth.orgis set - Compare values:
$record.orgequals$auth.org - Compare values:
$auth.org_roleis one ofadmin,owner
- Check a value:
3. Apply them to the table
In projects → Access:
Because the edit rule reads
org, members can’t move a project to another organization through the app.
4. Let a company sign up
When someone signs up, create their organization and switch into it:src/onboarding.ts
switchOrg, the session’s org and org_role are set and TOKEN_REFRESHED fires.
5. Invite colleagues
An admin or owner invites by email, with a role:accept-invite page with a token. The person signs in or signs up there, then your page accepts:
src/accept-invite.ts
redirectTo must be one of your allowed addresses under Users & auth → Domains. See Invitations.
6. Work inside the organization
Create records with the active organization, and list without filters, since the rule filters for you:src/projects.ts
7. Switch between organizations
src/switcher.ts
TOKEN_REFRESHED in onAuthStateChange and reload lists, so nothing from the previous organization stays on screen. switchOrg(null) leaves organization mode.
To sign straight into one: signInWithPassword({ email, password, org: "acme" }).
8. Files and live updates per organization
Use the same idea everywhere:- Files: put the organization first in the key (
acme/contracts/2026.pdf) and use the rule auth.org (plus $auth.org is set) on the bucket. See Rules on storage. - Channels: name them
org:acme:…and add a channel rule that requires the organization. See Rules on realtime.
9. Test the boundary
test/tenancy.test.ts
Server-side and staff access
- Your own backend acting for a person: pass their token, so the rules apply (Node.js).
- Your support staff across all organizations: use a separate admin tool with a secret key, rather than adding a global role to customer-facing rules. If you must, add Any of: Has role
platform_support;team_member.
Troubleshooting
Organizations
Members, roles, teams and metadata.
Recipes: teams
More multi-tenant rules.