Organizations
Add multi-tenant organizations with member roles, email invitations, owner and admin permissions, and billing scoped per user or per team.
Multi-tenancy is owned by @repo/auth via the Better Auth organization plugin and governed by config.tenancy. When multiTenant is true (the default), users create and join organizations; when false, the app is single-user and all team UI disappears.
Configuration
Everything is driven by config.tenancy:
// config.tenancy - the shipped default
tenancy: {
multiTenant: true, // teams on/off
organizationLimit: 5, // max orgs a user may create
billingScope: "user", // "user" | "organization"
}config.tenancy is a discriminated union: { multiTenant: false } for single-tenant, or { multiTenant: true; organizationLimit?: number; billingScope } for teams.
| Key | Type | Default | Description |
|---|---|---|---|
multiTenant | boolean | true | Master switch. false = single-tenant, no org UI. |
organizationLimit | number | 5 | Max organizations one user can create (multi-tenant only). |
billingScope | "user" | "organization" | "user" | Whether subscriptions attach to the user or the organization. |
Read effective values via the @repo/config helpers, never config.tenancy directly: getBillingScope() and getOrganizationLimit() resolve the single-tenant fallbacks for you.
What multi-tenancy gives you
With multiTenant: true, the organization plugin adds:
- Roles: every member is one of
member,admin, orowner; the creator becomesowner. - Members: users belong to one or more orgs; the active org is tracked on the session, set to the most recently joined membership on login.
- Invitations: owners/admins invite by email; the invitee opens
/accept-invitation/{id}to accept and join with the assigned role. - Notifications:
@repo/notificationsfires on member joined, member removed, and role changed (not on the invite itself). - Audit: every invitation is recorded in the audit logs. The org activity feed reads those logs and is restricted to
owner/admin.
Authorization rules (who can invite, remove, or change billing) are role-based - see Authorization.
Billing scope
billingScope decides who owns a subscription:
| Value | Default plan + credits seed onto | Seeded at | Use when |
|---|---|---|---|
"user" | The individual user (default) | User signup | B2C / per-seat products |
"organization" | The organization, shared by all members | Organization creation | B2B / team plans |
The hook seeds pricingConfig.defaultPlan and its credits onto the user (on signup) when scope is "user", or onto the org (when it is created) when "organization".
Set billingScope before going live. Switching it after customers subscribe re-points where new subscription records attach and can orphan existing ones.
Plans, checkout, and the customer portal read this scope automatically - see Plans and pricing.
When multiTenant is false
Setting config.tenancy = { multiTenant: false } hides all team surfaces:
- No organization creation, switcher, members, or invitations UI; org-gated nav and admin pages disappear.
getOrganizationLimit()returns1.getBillingScope()forces"user"- subscriptions always attach to the user.- No schema changes needed; the organization tables simply go unused.
Frequently asked questions
Can a user belong to more than one organization?
Yes. Membership is many-to-many; users switch the active org per session. organizationLimit only caps how many orgs each user can create, not join.
What happens to billing if I switch billingScope after launch?
New subscriptions follow the new scope, but existing records stay where they were created. Change it before taking real payments to avoid orphaned subscriptions.
Who can invite or remove members?
Role-based: owner and admin manage members and invitations; member cannot. The exact permission matrix lives in the authorization layer.