Claude
Skills
Sign in
Back

clerk-orgs

Included with Lifetime
$97 forever

Clerk Organizations for B2B SaaS - create multi-tenant apps with org switching, role-based access, verified domains, and enterprise SSO. Use for team workspaces, RBAC, org-based routing, member management.

General

What this skill does


# Organizations (B2B SaaS)

> **STOP — prerequisite.** Organizations must be enabled before any org-related API, hook, or component works. Two paths: (1) [Dashboard → Organizations settings](https://dashboard.clerk.com/last-active?path=organizations-settings), or (2) `clerk enable orgs` (see "Agent-first: Programmatic org management" below). Pick the Membership mode deliberately: `Membership required` (default since 2025-08-22) routes signed-in users through the `choose-organization` task and disables personal accounts, while `Membership optional` keeps personal accounts available for B2C + B2B coexistence. Pick `optional` if you need personal subscriptions alongside org subscriptions.
>
> **Version**: This skill targets current SDKs (`@clerk/nextjs` v7+, `@clerk/react` v6+ — Core 3). Core 2 differences are noted inline with `> **Core 2 ONLY (skip if current SDK):**` callouts — see `clerk` skill for the full version table.

## Quick Start

1. **Enable Organizations** — via [Dashboard → Organizations settings](https://dashboard.clerk.com/last-active?path=organizations-settings) or `clerk enable orgs` (see Agent-first section). Pick `Membership required` (B2B-only) or `Membership optional` (B2C + B2B).
2. **Create an org** — via `<OrganizationSwitcher />`, `<CreateOrganization />`, or programmatically with `clerkClient().organizations.createOrganization()`.
3. **Protect routes** — read `orgId` / `orgSlug` from `auth()` and gate with `has({ role })` or `has({ permission })`.
4. **Manage members** — send invitations via Backend API or the built-in `<OrganizationProfile />` tab.
5. **Cap membership** — set `maxAllowedMemberships` at org creation or pick a seat-limited Billing Plan (see `clerk-billing` skill).

## What Do You Need?

| Task | Reference |
|------|-----------|
| System permissions catalog, custom roles, role sets | references/roles-permissions.md |
| Invitation lifecycle (create, list, revoke, built-in UI) | references/invitations.md |
| Enterprise SSO setup, provider field access, domain verification | references/enterprise-sso.md |
| Next.js adaptations for orgs (role/permission middleware, slug invariants, orgId-scoped writes) | references/nextjs-patterns.md |

## References

| Reference | Description |
|-----------|-------------|
| `references/roles-permissions.md` | Default + custom roles, System Permissions catalog, permission naming |
| `references/invitations.md` | Backend API for invitations + built-in UI |
| `references/enterprise-sso.md` | SAML/OIDC per-org, domain verification, correct field access |
| `references/nextjs-patterns.md` | Next.js adaptations specific to orgs. For generic Next.js patterns see `clerk-nextjs-patterns` skill. |

## Dashboard shortcuts

| Action | URL |
|---|---|
| Enable Organizations + Membership mode | `https://dashboard.clerk.com/last-active?path=organizations-settings` |
| Manage roles + permissions | `https://dashboard.clerk.com/last-active?path=organizations-settings/roles` |
| Create/edit an organization | `https://dashboard.clerk.com/last-active?path=organizations` |
| Webhooks for org events | `https://dashboard.clerk.com/last-active?path=webhooks` |

## Agent-first: Programmatic org management

Org settings (enable toggle, membership cap, admin delete, domains) are patchable via PLAPI Instance Config. Org CRUD + memberships + invitations live in BAPI. Useful for agents seeding orgs, replicating settings across instances, or version-controlling org structure.

Pre-req: project linked (`clerk auth login` + `clerk link`, see `clerk-setup`).

### Enable Organizations + settings via CLI

```bash
clerk enable orgs
```

For additional settings (membership cap, verified domains, admin delete), patch the instance config:

```bash
clerk api --platform PATCH /v1/platform/applications/<app_id>/instances/<ins_id>/config \
  -d '{"organization_settings":{"max_allowed_memberships":50,"domains_enabled":true,"admin_delete_enabled":true}}'
```

### Create / list / delete orgs (BAPI)

```bash
# Create:
clerk api -X POST /v1/organizations \
  -d '{"name":"Acme","slug":"acme","created_by":"user_xxx","max_allowed_memberships":10}'

# List:
clerk api /v1/organizations --query 'limit=20'

# Get one:
clerk api /v1/organizations/<org_id>

# Update:
clerk api -X PATCH /v1/organizations/<org_id> -d '{"name":"Acme Inc."}'

# Delete:
clerk api -X DELETE /v1/organizations/<org_id>
```

### Memberships

```bash
# Add a user to an org:
clerk api -X POST /v1/organizations/<org_id>/memberships \
  -d '{"user_id":"user_xxx","role":"org:admin"}'

# List members:
clerk api /v1/organizations/<org_id>/memberships --query 'limit=50'

# Update role:
clerk api -X PATCH /v1/organizations/<org_id>/memberships/<user_id> \
  -d '{"role":"org:member"}'

# Remove:
clerk api -X DELETE /v1/organizations/<org_id>/memberships/<user_id>
```

### Invitations

```bash
# Send:
clerk api -X POST /v1/organizations/<org_id>/invitations \
  -d '{"email_address":"[email protected]","role":"org:member","redirect_url":"https://app.com/accept"}'

# List pending:
clerk api /v1/organizations/<org_id>/invitations --query 'status=pending'

# Revoke:
clerk api -X POST /v1/organizations/<org_id>/invitations/<inv_id>/revoke \
  -d '{"requesting_user_id":"user_xxx"}'
```

### Notes

- This handles **org config + CRUD**. Subscription / billing for orgs (org plans, seat-limit pricing) flows through `clerk-billing` skill.
- Roles + permissions catalog is editable in `references/roles-permissions.md`. Custom role creation goes through `clerk config patch` (instance-level role definitions) — see Dashboard's role editor for the UX equivalent.
- For SSO / verified domain provisioning, see `references/enterprise-sso.md`.

## Documentation

- [Overview](https://clerk.com/docs/guides/organizations/overview)
- [Configure + enable](https://clerk.com/docs/guides/organizations/configure)
- [Roles and permissions](https://clerk.com/docs/guides/organizations/control-access/roles-and-permissions)
- [Check access](https://clerk.com/docs/guides/organizations/control-access/check-access)
- [Invitations](https://clerk.com/docs/guides/organizations/add-members/invitations)
- [OrganizationSwitcher](https://clerk.com/docs/reference/components/organization/organization-switcher)
- [Verified domains](https://clerk.com/docs/guides/organizations/add-members/verified-domains)
- [Enterprise SSO](https://clerk.com/docs/guides/organizations/add-members/sso)

## Key Patterns

Examples use `@clerk/nextjs` by default. For other frameworks swap the import to `@clerk/react` (Vite/CRA), `@clerk/astro/components`, `@clerk/vue`, `@clerk/expo`, `@clerk/react-router`, or `@clerk/tanstack-react-start` — the feature-level APIs (`has()`, `orgId`, `<OrganizationSwitcher />`, `<Show>`) are identical across SDKs. Framework-specific patterns (middleware, redirects) live in `references/nextjs-patterns.md`.

### 1. Read Organization from Auth

Server-side access to active organization:

```typescript
import { auth } from '@clerk/nextjs/server'

const { orgId, orgSlug, orgRole } = await auth()
if (!orgId) {
  // user has no active org — either not in any, or viewing Personal Account
}
```

`auth()` is Next.js-specific. Equivalent server-side accessors per SDK: `auth(event)` (Nuxt via `event.context.auth()`), `context.locals.auth()` (Astro), `getAuth(req)` (Express, after `clerkMiddleware()`). Client-side: `useAuth()` (React-based SDKs) or composables (Vue/Nuxt). All return the same `orgId` / `orgSlug` / `orgRole` shape.

### 2. Dynamic Routes with Org Slug

Route-per-org pattern works in any framework supporting file-based dynamic routes. Next.js example:

```
app/orgs/[slug]/page.tsx
app/orgs/[slug]/settings/page.tsx
```

Always verify the URL slug matches the active org slug — otherwise users can hit `/orgs/other-org/...` with a stale `orgSlug` in their session:

```typescript
export default async function OrgPage({ params }: { params: { slug: string } }) {
  const { orgSlug } = await auth()
  if (orgSlug !== pa
Files: 6
Size: 48.7 KB
Complexity: 53/100
Category: General

Related in General