Organizations
Org-scoped tenancy — memberships, roles, and invites.
Organizations add multi-tenancy on top of auth via Better Auth's organization
plugin. Every user belongs to one or more orgs; the app's data is scoped to the
session's active organization, and members carry a role (owner /
member). The UI ships an org switcher, an org settings surface (general,
members, invites, danger zone), and an invitation-accept flow.
Core feature
Orgs is a core feature (core: true, requires: ["auth"]). It is never
pruned: the app is org-scoped by construction, and most optional features hang
their data off an Organization.
What it does
- Tenancy —
Session.activeOrganizationIdscopes requests;orgProcedurereads it server-side. A session defaults to the user's personal org. - Memberships & roles — an owner plus members (
Membership.role), surfaced inOrgSettings→ members table. - Invites — email invitations (
Invite) with pending/accepted status and an expiry; the row id is the credential (acceptInvitation({ invitationId })). - Switching —
OrgSwitcherchanges the active org on the session. - Danger zone — rename, and org deletion with the usual guards.
Models it adds
Better Auth's organization plugin models, with modelName overrides keeping
the friendlier names (prisma/schema.prisma):
| Model | Purpose |
|---|---|
Organization | The tenant: name, unique slug, logo, metadata. |
Membership | User ↔ org link carrying role. |
Invite | Pending email invitation (email, role, status, expiry, inviter). |
Session.activeOrganizationId (a bare column, not a relation) tracks the
scoped org. Organization is also the anchor for optional features' data —
subscription, flagOverrides, usageEvents, apiKeys, files, auditLogs
are all marker-wrapped relations that prune with their features.
Env it needs
None.
Composition
requires: ["auth"]— memberships and invites referenceUser.- Dependents — nearly every optional feature requires orgs, directly or
transitively:
billing,api-keys,files,audit-log,admin(directly), andflags,usage,marketing(through billing). - billing hooks membership changes: the orgs add/remove-member mutations
call
enqueueSeatsSyncbehind@feature:billingmarkers to reconcile Stripe seat quantity. - email renders the org-invite template through
enqueueEmailat a marked call site (console fallback when email is pruned).
What pruning removes
Nothing — orgs is core and cannot be deselected. What does prune is the set of
@feature-marked cross-relations other features attach to Organization; each
disappears with its own feature, leaving Organization/Membership/Invite
intact.