---
title: Organizations
description: B2B workspaces, members, invitations, and roles with convex-auth.
sidebar:
  order: 9
---

`convex-auth` supports multi-tenant organizations natively in Convex. Users, organizations, memberships, invitations, and roles all live in the `convexAuth` component tables. The `@vortex-api/convex-auth/react` package ships uncontrolled UI components that you wire to your own Convex queries and mutations.

## How it works

Organizations are stored as first-class data in the `convexAuth` component. Every organization has:

- a `name`, `slug`, and `imageUrl`
- a set of members with a `roleKey`
- pending invitations with an `expiresAt` and `roleKey`
- customizable role templates with permissions

Your app keeps local anchor rows (for example, a `workspaces` table) that map one-to-one to the component organization rows. The `createConvexAuthOrganizationOperations` factory returns typed reader/writer helpers that keep the component data and your local data in sync.

## Mount the organizations component

If you only need the core auth runtime, you do not have to mount this. If you need orgs, mount it alongside the core component:

```ts convex/convex.config.ts
import { defineApp } from "convex/server";
import { v } from "convex/values";
import authCore from "@vortex-api/convex-auth/convex.config/core";
import authOrganizations from "@vortex-api/convex-auth/convex.config/organizations";

const app = defineApp({
  env: {
    JWT_PRIVATE_KEY: v.string(),
    JWKS: v.string(),
  },
});

app.use(authCore, {
  env: {
    JWT_PRIVATE_KEY: app.env.JWT_PRIVATE_KEY,
    JWKS: app.env.JWKS,
  },
});

app.use(authOrganizations, {
  env: {
    JWT_PRIVATE_KEY: app.env.JWT_PRIVATE_KEY,
    JWKS: app.env.JWKS,
  },
});

export default app;
```

> **Info**
>
> The full `convexAuth` component already includes the core tables. The `organizations` component
> adds `auth_organizations`, `auth_organization_members`, `auth_organization_invitations`, and
> `auth_organization_roles`.

## React components

**[ConvexCreateOrganization](/convex-auth/organizations)**

A controlled form for name, slug, and logo. Calls your `onCreate` callback.

**[ConvexOrganizationList](/convex-auth/organizations)**

Lists a user's organizations and pending invitations.

**[ConvexOrganizationSwitcher](/convex-auth/organizations)**

A dropdown to switch between workspaces.

**[ConvexOrganizationProfile](/convex-auth/organizations)**

Edits the org name, slug, and image.

**[ConvexOrganizationMembers](/convex-auth/organizations)**

Invites members, lists members, and manages member status.

**[ConvexOrganizationRoleManager](/convex-auth/organizations)**

Creates and lists custom roles with permission checklists.

## Create an organization

```tsx src/CreateOrganization.tsx
import { ConvexCreateOrganization } from "@vortex-api/convex-auth/react";
import { useMutation } from "convex/react";
import { api } from "../convex/_generated/api";

export function CreateOrganization() {
  const create = useMutation(api.organizations.createOrganization);

  return (
    <ConvexCreateOrganization
      onCreate={async ({ name, slug, imageUrl }) => {
        await create({ name, slug });
      }}
      defaultName="Acme"
      defaultSlug="acme"
    />
  );
}
```

`ConvexCreateOrganization` calls `onCreate` with `{ name, slug, imageUrl? }`. The component validates the slug format and required fields. Your `createOrganization` mutation is responsible for:

1. Calling the component writer to insert the org.
2. Creating or ensuring default roles.
3. Creating an owner membership and setting the active organization.

## Switch workspaces

```tsx src/WorkspaceSwitcher.tsx
import { ConvexOrganizationSwitcher } from "@vortex-api/convex-auth/react";
import { useMutation, useQuery } from "convex/react";
import { api } from "../convex/_generated/api";

export function WorkspaceSwitcher() {
  const organizations = useQuery(api.organizations.listMyOrganizations) ?? [];
  const active = useQuery(api.organizations.getActiveOrganization);
  const setActive = useMutation(api.organizations.setActiveOrganization);
  const createOrganization = useMutation(api.organizations.createOrganization);

  return (
    <ConvexOrganizationSwitcher
      organizations={organizations}
      currentOrganizationId={active?._id ?? null}
      currentOrganization={active ?? null}
      onSelectOrganization={async (id) => await setActive({ organizationId: id })}
      onInPlaceCreateOrganization={async (name) => {
        await createOrganization({ name });
      }}
    />
  );
}
```

## Members and roles

```tsx src/WorkspaceSettings.tsx
import {
  ConvexOrganizationMembersSurface,
  ConvexOrganizationRoleManagerSurface,
  useConvexOrganizationRefs,
} from "@vortex-api/convex-auth/react";
import { useQuery } from "convex/react";
import { api } from "../convex/_generated/api";

export function WorkspaceSettings() {
  const active = useQuery(api.organizations.getActiveOrganization);
  const refs = useConvexOrganizationRefs(api);

  if (!active) return null;

  return (
    <>
      <ConvexOrganizationMembersSurface
        organizationId={active._id}
        roleOptions={["owner", "admin", "manager", "member", "viewer"]}
        refs={refs.members}
      />
      <ConvexOrganizationRoleManagerSurface canCreateRoles refs={refs.roles} />
    </>
  );
}
```

`useConvexOrganizationRefs(api)` maps the consumer's `api.organizations.*` functions to the `refs` the presentational components expect. The consumer functions must match the names and shapes used in the React demo:

- `listMembers`, `inviteMember`, `reactivateMember`, `setMemberRole`, `suspendMember`
- `listRoles`, `listPermissions`, `createRole`

See `examples/react/convex/organizations.ts` for a working reference implementation.

## Run the example

The React demo lives in `examples/react`. To see the full workspace flow locally:

```bash
pnpm dlx convex dev
pnpm --filter examples/react dev
```

Then sign up, create a workspace, invite a second account, and switch members/roles.

## Server-side operations

The `convex-auth` component exposes the organization tables, but the public helpers are low-level. For a working consumer, see `examples/react/convex/organizations.ts`.

If you are building your own server surface, import `createConvexAuthOrganizationOperations` from `@vortex-api/convex-auth/convex` and pass it:

- `component` — the `components.convexAuthOrganizations` handle.
- `resolveLocalOrganizationId` and `resolveLocalUserId` — bridge lookup callbacks.
- `roleCatalog` — a `roleKey → permissions[]` map.
- `validateRoleKey` — a type guard for your consumer role keys.

It returns a typed suite of `read` and `write` functions for organizations, members, invitations, roles, and API keys. Use these inside your own Convex actions and mutations.

> **Warning**
>
> The `createConvexAuthOrganizationOperations` API is **increment 3** and still internal-facing. The
> React components above are the stable, public surface. If you need the detailed server action
> reference, open an issue and we will expand this page.
