Skip to main content
WeGotWork supports multi-organization workflows, allowing users to belong to multiple organizations and switch between them seamlessly.

Organization membership

Users can be members of multiple organizations through the Member model (or OrganizationUser in some implementations):
model Member {
  id             String       @id @default(cuid())
  organizationId String
  organization   Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
  userId         String
  user           User         @relation(fields: [userId], references: [id], onDelete: Cascade)
  role           String       @default("member")
  createdAt      DateTime     @default(now())

  @@index([organizationId])
  @@index([userId])
  @@map("member")
}

Current organization tracking

Users can set an active organization using currentOrganizationId (stored on the User model) or activeOrganizationId (stored on the Session model in some implementations).

User-based tracking

model User {
  id                    String             @id
  name                  String
  email                 String
  currentOrganizationId String?
  currentOrganization   Organization?      @relation(fields: [currentOrganizationId], references: [id], onDelete: SetNull)
  // ... other fields
}

Session-based tracking

model Session {
  id                   String   @id
  activeOrganizationId String?
  // ... other fields
}

Switching organizations

Implement organization switching to allow users to change their active context:
export async function SetCurrentOrganization(organizationId: string) {
  const session = await auth.api.getSession({
    headers: await headers(),
  });
  
  if (!session) {
    return {
      error: true,
      message: "user not logged in."
    };
  }

  // Verify user is a member of the organization
  const isMember = await prisma.organizationUser.findFirst({
    where: {
      userId: session.user.id,
      organizationId: organizationId
    }
  });

  if (!isMember) {
    return {
      error: true,
      message: "user not member of organization"
    };
  }

  // Update current organization
  await prisma.user.update({
    where: { id: session.user.id },
    data: { currentOrganizationId: organizationId }
  });

  revalidatePath("/overview");
  
  return {
    error: false,
    message: "Updated Organization Successfully"
  };
}
Always verify that a user is a member of an organization before allowing them to switch to it.

Listing user organizations

Retrieve all organizations a user belongs to:
export async function UserOrganizations() {
  const session = await auth.api.getSession({
    headers: await headers()
  });

  if (!session) {
    redirect("/");
  }

  const organizations = await prisma.user.findUnique({
    where: { id: session.user.id },
    include: {
      userOrganizations: {
        include: {
          organization: true
        }
      }
    }
  });

  return {
    userOrganizations: organizations?.userOrganizations
  };
}

Filtering by organization

When querying data, always filter by the current organization to ensure users only see data they have access to:

Jobs scoped to organization

const jobs = await prisma.job.findMany({
  where: {
    organizationId: currentOrganizationId
  },
  include: {
    category: true,
    applicants: true
  }
});

Verifying organization access

const job = await prisma.job.findFirst({
  where: {
    id: jobId,
    organization: {
      members: {
        some: {
          userId: session.user.id
        }
      }
    }
  }
});

if (!job) {
  throw new Error("You are not authorized to access this job");
}

Organization roles

Differentiate between organization owners and members:
enum Role {
  owner
  member
}
Check user role before allowing sensitive operations:
const membership = await prisma.organizationUser.findFirst({
  where: {
    userId: session.user.id,
    organizationId: organizationId
  }
});

if (membership?.role !== "owner") {
  throw new Error("Only organization owners can perform this action");
}

Creating organizations

When a user creates an organization, automatically make them an owner:
const organization = await prisma.organization.create({
  data: {
    name: "Acme Corp",
    slug: "acme-corp",
    members: {
      create: {
        userId: session.user.id,
        role: "owner"
      }
    }
  }
});

// Set as current organization
await prisma.user.update({
  where: { id: session.user.id },
  data: { currentOrganizationId: organization.id }
});
Automatically set newly created organizations as the user’s current organization for a smoother experience.

Inviting users to organizations

Allow organization members to invite others:
const invitation = await prisma.organizationInvite.create({
  data: {
    email: inviteeEmail,
    role: "member",
    organizationId: organizationId,
    createdAt: new Date()
  }
});

// Send invitation email
await sendInvitationEmail(inviteeEmail, invitation.id);

Organization context in UI

Display the current organization and provide a switcher:
export function OrganizationSwitcher() {
  const { userOrganizations } = await UserOrganizations();
  const currentOrgId = session.user.currentOrganizationId;

  return (
    <Select
      value={currentOrgId}
      onValueChange={SetCurrentOrganization}
    >
      {userOrganizations?.map((membership) => (
        <SelectItem
          key={membership.organization.id}
          value={membership.organization.id}
        >
          {membership.organization.name}
        </SelectItem>
      ))}
    </Select>
  );
}

Best practices

Never query jobs, applicants, or other organization-specific data without filtering by organization ID to prevent data leaks.
Always check that a user is actually a member of an organization before allowing them to switch to it.
Use onDelete: SetNull for currentOrganizationId so users aren’t left in an invalid state if their current organization is deleted.
Make it clear which organization the user is currently working in, especially in the navigation or header.
If a user doesn’t have a current organization set, automatically select their first organization or prompt them to choose one.

Build docs developers (and LLMs) love