Hype StackHypeStack

Search

Search the packs, templates, docs, and pages

Organizations

Organizations are the multi-tenant boundary in every starter. Users belong to organizations, invitations bring new members in, and API routes scope work to the active organizationId on the request context.

The free auth starter has the same model underneath but hides it: every account gets one organization named Personal workspace at creation, and there is no switcher, no members page, and no way to send an invitation. That is what lets every feature pack, all of which scope data to the active organization, install on it unchanged. Swap to a SaaS starter later and the personal workspace becomes the user's first team.

Credential-free setup notes live on the starter pack pages. This page is the domain model and code paths.

What ships with a starter

ConceptRole
OrganizationTenant boundary for data and settings
Membership + roleTies a user to an org with a permission preset (admin, member, ...)
InvitationEmail invite into an organization
Permissions (CASL)Server-side hasAccess checks mirrored in the UI
OnboardingFirst-time flow to create or join an org before the private app

Where the code lives

PiecePath pattern
Organization featuresapps/backend/src/features/organizations/modules/
Organization routesapps/backend/src/routes/organizations/
Invitation socketsapps/backend/src/sockets/invitations/
Permission presets / subjectspackages/enums (or the enums package your stack installs)
hasAccess middlewareapps/backend/src/middleware/permissions/has-access.ts
Frontend org settingsapps/frontend/src/features/settings/modules/organization-tab/
Onboarding routesapps/frontend/src/routes/onboarding/

WorkOS vs Better Auth membership storage

WorkOS starterBetter Auth starter
MembershipsWorkOS organization memberships APILocal Prisma Member + Organization models
InvitationsLocal OrganizationInvitation plus emailSame invitation feature modules; Better Auth's own Invitation model is unused by the app flow
Org settings / logosLocal Prisma + storage uploadsSame

Both starters expose the same product UX: create org, invite members, manage roles, enforce hasAccess on routes.

Permission flow

From session to route gate

  1. withAuthUser

    Resolves the signed-in user and active organization membership.

  2. resolvePermissionsForMembership

    Loads the role permissions for that membership (WorkOS API or Prisma, depending on starter).

  3. buildAbilityFromPermissions

    Turns the permission list into a CASL ability on the Hono context.

  4. hasAccess({ action, subject })

    Route middleware denies the request when ability.can fails.

When you add a new domain (for example teams or projects), register subjects and grant them on the right roles. The teams pack notes that you may need to add CASL subjects manually after install.

Invitations

Organization invitation modules handle send, accept, and resend. Accepting an invite attaches the user to the org and continues into the private app. Email delivery needs Resend configured; see Mailing.

Feature flags

The two SaaS starters ship per-organization feature flags. Flags are defined in code, in packages/enums/src/feature-flags/catalog.ts, so a new flag is a typed key reviewed in a pull request, not a row someone typed into a dashboard:

ts
export const FEATURE_FLAGS = [
  {
    key: "beta-reports",
    name: "Reports",
    description: "The new reporting screens",
    kind: FeatureFlagKind.BETA,
    defaultEnabled: false,
  },
] as const satisfies readonly FeatureFlagDefinition[];

The catalog ships empty. The database stores only per-organization overrides (OrganizationFeatureFlag), and resolution is one pure function: an override wins, otherwise the default, and a key no longer in the catalog is ignored. Retiring a flag is deleting its entry, with no migration.

PieceWhere
Resolved flags APIGET /organizations/feature-flags
Backend gatewithFeature("beta-reports") middleware, or isFeatureEnabled inside a module
Frontend gateuseFeatureFlag("beta-reports") or <FeatureGate flag="beta-reports"> in features/feature-flags/, same on mobile and the extension
AdminA Flags tab on every organization's detail page, with set and reset per flag

There are no percentage rollouts and no per-user targeting. The unit is the organization, which is also the billing unit, so an entitlement flag and a plan line up. The free auth starter does not ship flags.

The admin org page is extensible the same way: feature packs add tabs next to Flags through the orgDetailsTabs manifest field. The AI chat pack uses it for its per-organization usage tab.

Teams pack relationship

pack-teams adds teams inside an organization (Team, TeamMember, team invitations). It does not replace org membership. Org role still gates who can manage teams; team membership is a second layer for collaboration inside one tenant.

pack-projects is the same idea for projects and project members.

Practical guidance

  • Scope queries by organizationId from context. Do not trust a client-supplied org id without membership checks.
  • Keep new permission subjects in the shared enums package so frontend and backend stay aligned.
  • For admin-wide views across all orgs, use the admin app, not the customer frontend.
Sponsor open source

Every purchase and sponsorship funds my 8+ years of work on open source given freely to the community. It keeps the lights on, funds new packs, and keeps the ecosystem alive. Even a small tier means a lot. Thank you!

Sponsor on GitHub