General
Organizations

Configure

Learn how to configure organizations in your application.

Organizations are configured in the Better Auth setup in lib/auth/index.ts. The organization plugin is already enabled by default.

Organization Plugin Configuration

The organization plugin is configured in lib/auth/index.ts:

lib/auth/index.ts
import { organization } from 'better-auth/plugins';

export const auth = betterAuth({
  // ... other config
  plugins: [
    organization({
      // Organization configuration
    })
  ]
});

Default Behavior

By default, organizations are:

  • Enabled - Users can create and join organizations
  • Optional - Users don't need to be in an organization to use the app
  • Visible - Organization selection is shown in the UI
  • User-creatable - Users can create new organizations

Customizing Organization Behavior

Require Organization

To require users to be in an organization to access the application, you can add middleware or route protection:

middleware.ts
import { redirect } from 'next/navigation';

import { getSession } from '@/lib/auth/server';

export async function middleware(request: NextRequest) {
  const session = await getSession();

  if (!session) {
    return redirect('/auth/sign-in');
  }

  // Check if user has an active organization
  if (!session.session.activeOrganizationId) {
    // Redirect to organization creation/selection
    return redirect('/dashboard/onboarding');
  }
}

Hide Organization Selection

If you want to build a single-tenant application where users should only be members of one organization, you can hide the organization switcher in your UI components.

Disable Organization Creation

To prevent users from creating new organizations (invite-only), you can restrict the create organization functionality:

trpc/routers/organization.ts
import { createTRPCRouter, protectedProcedure } from '@/trpc/init';
import { TRPCError } from '@trpc/server';
import { z } from 'zod';

export const organizationRouter = createTRPCRouter({
  create: protectedProcedure
    .input(z.object({ name: z.string() }))
    .mutation(async ({ input, ctx }) => {
      // Check if user is allowed to create organizations
      // You can add custom logic here

      // For invite-only, you might want to disable this entirely
      throw new TRPCError({
        code: 'FORBIDDEN',
        message: 'Organization creation is disabled'
      });
    })
});

Organization Settings

You can customize organization behavior through Better Auth's organization plugin options:

lib/auth/index.ts
organization({
  // Customize member roles
  memberRoles: ['owner', 'admin', 'member'],

  // Customize invitation behavior
  invitation: {
    // Invitation expiration (in seconds)
    expiresIn: 7 * 24 * 60 * 60 // 7 days
  },

  // Custom hooks for organization events
  hooks: {
    afterCreate: async ({ organization, user }) => {
      // Custom logic after organization creation
    },
    afterAddMember: async ({ organization, user }) => {
      // Custom logic after adding a member
    }
  }
});

Invite-Only Organizations

To create an invite-only organization setup:

  1. Disable organization creation - Remove or restrict the create organization functionality
  2. Require invitations - Only allow users to join via invitations
  3. Control invitations - Only allow admins/owners to send invitations

The starter kit already includes invitation functionality through Better Auth's organization plugin.

Best Practices

  1. Use organization slugs - Use URL-friendly slugs for organization identification
  2. Validate membership - Always verify user membership before allowing access
  3. Scope data - Always scope data queries by organization ID
  4. Handle edge cases - Handle cases where users have no organizations
  5. Role-based access - Use roles to control what users can do