Generated banner for Clerk Orgs
Generated logo for Clerk Orgs

Clerk Orgs

ClerkOfficialCreated by clerk

  • Skill
  • Tool integration
  • Software development
  • MIT
  • No issues found

From the author

Clerk Organizations for B2B and multi-tenant apps - org switching, roles and permissions, verified domains, and enterprise SSO. Use for team workspaces, RBAC, org-scoped routing, member management. Also load this when a project treats teams, workspaces, tenants, or companies as its customers - shared accounts, inviting teammates, per-seat pricing, per-company data isolation - even when the words "organization" or "B2B" are never used.
— the description by clerk

From the skill’s files

Taken from the skill’s own files (its description, section headings and stated usage). Not an AutoGineer summary, and not written by the author as one.

Clerk Organizations for B2B and multi-tenant apps - org switching, roles and permissions, verified domains, and enterprise SSO. Use for team workspaces, RBAC, org-scoped routing, member management. Also load this when a project treats teams, workspaces, tenants, or companies as its customers - shared accounts, inviting teammates, per-seat pricing, per-company data isolation - even when the words "organization" or "B2B" are never used. Decide before enabling anything. Read the project, count the signals, then ask the developer - do not enable Organizations silently.

What it does

  • Should this app use Organizations?
  • Quick Start
  • What Do You Need?
  • Dashboard shortcuts
  • Agent-first: Programmatic org management
  • Documentation

When to use it

  • Use for team workspaces, RBAC, org-scoped routing, member management.

Advantages

The skill’s files do not state this.

Usage examples

The skill’s files do not state this.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/clerk/clerk-orgs/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip clerk-orgs.zip -d .agents/skills

Documentation by clerk

Organizations (B2B SaaS)

STOP — prerequisite. Organizations must be enabled before any org-related API, hook, or component works. Two paths: (1) Dashboard → 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.

Should this app use Organizations?

Decide before enabling anything. Read the project, count the signals, then ask the developer - do not enable Organizations silently.

Signals this app is multi-tenant (recommend Organizations):

  • A model that groups users: Team, Workspace, Tenant, Company, Account

  • The same foreign key on most tables: workspace_id, team_id, account_id

  • Routes scoped to a tenant: /[workspace], /[slug]/settings, /t/:tenantId

  • "Invite your team", "members", "seats", or "admin" in UI copy or the README

  • A *_members join table, or hand-rolled role / permission columns

  • Per-seat or per-company pricing

Weaker signals - enough to raise the question, not to answer it:

  • Sharing or collaboration between individual users: a Share, Collaborator, or SharedWith table keyed on two user IDs

  • A role or permission column with no tenant to scope it to

  • "Collaborators", "shared with you", "invite a friend" in copy

Signals this app is single-user (do not recommend):

  • Every table hangs off user_id with no container above it, and nothing is shared

  • No invitation, membership, or sharing concept anywhere

  • Pricing is per person, or there is none

How to act:

What you foundWhat to do
2 or more strong signalsRecommend Organizations and name the signals you saw. New app: clerk init --template b2b-saas. Existing app: clerk enable orgs.
1 strong signal, or any weaker signalRaise it as an option, state the tradeoff, let the developer choose. Sharing between individual users is not multi-tenancy - a Share table pointing at two user IDs has no tenant - but it is often where a product grows one.
Nothing aboveDon't bring it up.

Never enable Organizations without asking. Enabling it also turns on Membership required, which routes every signed-in user through organization selection and disables personal accounts. That is wrong for any app that also serves individuals. If the app needs both, it wants Membership optional.

Quick Start

  1. Enable Organizations — via Dashboard → 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?

TaskReference
System permissions catalog, custom roles, role setsreferences/roles-permissions.md
Invitation lifecycle (create, list, revoke, built-in UI)references/invitations.md
Enterprise SSO setup, provider field access, domain verificationreferences/enterprise-sso.md
Next.js adaptations for orgs (per-page role/permission checks, slug invariants, orgId-scoped writes)references/nextjs-patterns.md
Org errors and symptoms (undefined orgId, has() returning false, no Personal Account)references/errors.md

References

ReferenceDescription
references/roles-permissions.mdDefault + custom roles, System Permissions catalog, permission naming
references/invitations.mdBackend API for invitations + built-in UI
references/enterprise-sso.mdSAML/OIDC per-org, domain verification, correct field access
references/nextjs-patterns.mdNext.js adaptations specific to orgs. For generic Next.js patterns see clerk-nextjs-patterns skill.
references/errors.mdError signatures with root causes and fixes

Dashboard shortcuts

ActionURL
Enable Organizations + Membership modehttps://dashboard.clerk.com/last-active?path=organizations-settings
Manage roles + permissionshttps://dashboard.clerk.com/last-active?path=organizations-settings/roles
Create/edit an organizationhttps://dashboard.clerk.com/last-active?path=organizations
Webhooks for org eventshttps://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: a linked project (clerk auth login + clerk link, see clerk-cli) — or an unclaimed app from clerk init: clerk enable orgs and org CRUD via clerk api work with no login at all.

Enable Organizations + settings via CLI
clerk enable orgs

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

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)
# 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?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
# 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?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
# 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?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

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:

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:

import { auth } from '@clerk/nextjs/server'
import { redirect } from 'next/navigation'

export default async function OrgPage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params
  const { orgSlug } = await auth()
  if (orgSlug !== slug) {
    redirect('/dashboard')  // or whatever your "no-access" flow is
  }
  return <div>Welcome to {orgSlug}</div>
}

In Next.js, add a loading.tsx next to a page like this one that gates its render with redirect(): with Cache Components (the create-next-app default), next build fails on request data read outside a <Suspense> boundary.

3. Role-Based Access Control
const { has } = await auth()

if (!has({ role: 'org:admin' })) {
  return <div>Admin access required</div>
}

Permission checks use the same has() surface, for custom Permissions you create in the Dashboard:

if (!has({ permission: 'org:invoices:create' })) {
  redirect('/unauthorized')
}

On the server, has({ permission }) works only with custom Permissions: System Permissions (org:sys_*) aren't in the session token, so checking one there always returns false. Clerk documents permission checks in <Show when={{ permission }}> for custom Permissions only. To require a System Permission, check a role that carries it (has({ role: 'org:admin' })).

Permission naming convention. System Permissions prefix with org:sys_; custom Permissions use org:<resource>:<action>. The full System Permissions catalog lives in references/roles-permissions.md — the short list is:

  • org:sys_memberships:{read, manage}

  • org:sys_profile:{manage, delete}

  • org:sys_domains:{read, manage}

  • org:sys_billing:{read, manage}

Do NOT invent names like org:create, org:manage_members, org:update_metadata — those are not real permission slugs. See references/roles-permissions.md for custom roles and the permission table.

4. Conditional Rendering with <Show>

In a Next.js Server Component, <Show> reads the session from the request, so wrap it in <Suspense>. In a Client Component, it reads client-side auth state and needs no boundary.

import { Show } from '@clerk/nextjs'
import { Suspense } from 'react'

<Suspense>
  <Show when={{ role: 'org:admin' }}>
    <AdminPanel />
  </Show>

  <Show when={{ permission: 'org:invoices:create' }}>
    <NewInvoiceButton />
  </Show>
</Suspense>

Core 2 ONLY (skip if current SDK): Use <Protect role="org:admin"> / <Protect permission="..."> instead of <Show>. <Show> replaced both <Protect> and <SignedIn>/<SignedOut> in Core 3.

Astro template syntax for the same component (imported from @clerk/astro/components):

<Show when={{ role: 'org:admin' }}>
  <AdminPanel />
</Show>
5. OrganizationSwitcher
import { OrganizationSwitcher } from '@clerk/nextjs'

<OrganizationSwitcher
  hidePersonal
  afterCreateOrganizationUrl="/orgs/:slug/dashboard"
  afterSelectOrganizationUrl="/orgs/:slug/dashboard"
/>

Key props:

  • hidePersonal: boolean — hide the Personal Account option. Defaults to false. Pass true for B2B-only apps.

  • afterCreateOrganizationUrl, afterSelectOrganizationUrl, afterLeaveOrganizationUrl, afterSelectPersonalUrl — navigation hooks. :slug is substituted at runtime.

  • createOrganizationMode, organizationProfileMode — 'modal' | 'navigation' (default 'modal').

The full prop list lives in the component reference.

6. Session Task — Choose Organization

When Membership required is enabled (the default), users without an org are routed through a choose-organization session task after sign-in. Clerk handles this automatically inside <SignIn />, but you can host the UI yourself:

import { ClerkProvider } from '@clerk/nextjs'

<ClerkProvider taskUrls={{ 'choose-organization': '/session-tasks/choose-organization' }}>
  {children}
</ClerkProvider>
// app/session-tasks/choose-organization/page.tsx
import { TaskChooseOrganization } from '@clerk/nextjs'

export default function Page() {
  return <TaskChooseOrganization redirectUrlComplete="/dashboard" />
}

TaskChooseOrganization ships as an imported component in the React-based SDKs (@clerk/nextjs, @clerk/react, @clerk/react-router, @clerk/tanstack-react-start). For the JS Frontend SDK (@clerk/clerk-js) the equivalent is clerk.mountTaskChooseOrganization(node) / clerk.unmountTaskChooseOrganization(node).

Core 2 ONLY (skip if current SDK): Session tasks aren't available. Force an org selection at sign-in by redirecting to a page that renders <OrganizationSwitcher hidePersonal />.

Default Roles + System Permissions

RoleDefault meaning
org:adminFull access — all System Permissions, can manage org + memberships
org:memberRead members + Read billing Permissions only

You can create up to 10 custom roles per instance in Dashboard → Organizations → Roles & Permissions. Role-per-org is controlled via Role Sets — see references/roles-permissions.md for the full model (custom roles, Creator/Default role settings, role sets, and the System Permissions catalog).

Billing Checks

has() also supports plan and feature checks when Clerk Billing is enabled:

const { has } = await auth()

has({ plan: 'gold' })        // subscription plan
has({ feature: 'widgets' })  // feature entitlement

Core 2 ONLY (skip if current SDK): has() only supports role and permission. Billing checks aren't available.

See clerk-billing for the full Billing surface and seat-limit plan model.

Enterprise SSO

Per-org SAML/OIDC. Configured in Dashboard → Configure → Enterprise Connections (or per-org: Organizations → select org → SSO Connections). The SSO connection owns its domain directly; no separate Verified Domain is required (and the two features are mutually exclusive on the same domain). Auto-join on first SSO sign-in uses JIT Provisioning, not Verified Domains. Key fact: the provider field lives on enterpriseConnection, not on enterpriseAccounts[0] directly. See references/enterprise-sso.md for the full flow and correct field access.

// Strategy name for Enterprise SSO (Core 3)
strategy: 'enterprise_sso'

Core 2 ONLY (skip if current SDK): Uses strategy: 'saml' and user.samlAccounts instead of user.enterpriseAccounts.

Gotchas

maxAllowedMemberships caps seats
const clerk = await clerkClient()
await clerk.organizations.createOrganization({
  name: 'Acme Corp',
  createdBy: userId,
  maxAllowedMemberships: 10,
})

// Update later:
await clerk.organizations.updateOrganization(orgId, {
  maxAllowedMemberships: 25,
})

For tier-based seat limits tied to a subscription, use a seat-limited Billing Plan (see clerk-billing).

Billing gates Permissions at the Feature level

When Clerk Billing is enabled, has({ permission: 'org:posts:edit' }) returns false if the Feature associated with that permission is not included in the organization's active Plan — even if the user has the Permission assigned via their role. Ensure the Feature is attached to the active Plan in Dashboard → Billing → Plans → Features.

Metadata updates REPLACE, not merge

updateOrganization({ publicMetadata }) overwrites all public metadata. Read first, spread, then write:

const org = await clerk.organizations.getOrganization({ organizationId: orgId })
await clerk.organizations.updateOrganization(orgId, {
  publicMetadata: { ...org.publicMetadata, newField: 'value' },
})

Applies identically to privateMetadata and to user metadata via clerkClient.users.updateUser.

Error Signatures (diagnose fast)

If org roles, permissions, or UI behave unexpectedly, check the organization error signatures before changing code. Configuration and session state cause many of these symptoms.

Authorization pattern

For a complete slug-scoped admin-page example, read Next.js organization patterns.

Invitations

For a server-side invitation example and the full lifecycle (list, revoke, bulk create, built-in UI), read references/invitations.md. Check a role that carries org:sys_memberships:manage; has() cannot check System Permissions directly.

Workflow

  1. Enable — Organizations + Membership mode in Dashboard

  2. Create org — via UI component or Backend API

  3. Invite members — Backend API or built-in UI, with inviterUserId

  4. Gate access — has({ role }), or has({ permission }) with a custom Permission. has() can't check System Permissions (org:sys_*)

  5. Scope routes — orgSlug === params.slug on every protected page

  6. Switch orgs — <OrganizationSwitcher /> handles the whole flow

See Also

  • clerk-setup — Initial Clerk install

  • clerk-billing — Seat-limit plans, per-plan billing, has({ plan }) / has({ feature })

  • clerk-webhooks — Sync org events to your database (organization.created, organizationMembership.*)

  • clerk-backend-api — Full Backend API reference

  • clerk-nextjs-patterns — Framework-specific middleware, server actions, caching

Files

evals/evals.json

{
	"skill_name": "clerk-orgs",
	"evals": [
		{
			"id": 1,
			"prompt": "i have a basic saas app with clerk auth. i need to add organization support so users can create teams and switch between them. the dashboard should be org-scoped so each team sees their own data. add an org switcher to the dashboard.",
			"expected_output": "Adds OrganizationSwitcher component, makes dashboard org-aware using orgId from auth(), adds org-scoped data access pattern",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Imports and renders OrganizationSwitcher from @clerk/nextjs",
				"Uses orgId from auth() in the dashboard to scope data to the current organization",
				"Handles the case where no organization is selected (prompts user to select or create one)",
				"Does NOT remove existing user authentication logic",
				"Dashboard page checks both userId and orgId"
			]
		},
		{
			"id": 2,
			"prompt": "my app needs role-based access control. i have an admin settings page that only org admins should access. regular members should see the dashboard but not settings. use clerk's org roles to enforce this.",
			"expected_output": "Adds orgRole check to settings page, redirects non-admins, uses auth() to get role",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Uses has({ role: 'org:admin' }) from auth() rather than comparing orgRole string directly",
				"Destructures has from the result of await auth() (not from useAuth or a non-awaited call)",
				"Does NOT hardcode role strings without using Clerk's role system",
				"If it uses a permission check, passes a custom Permission slug (org:<resource>:<action>) to has(), NOT a System Permission (org:sys_*, which has() can't check) and NOT an invented slug like org:manage_members, org:create, or org:update_metadata",
				"Settings page shows org-level configuration options",
				"Regular members can still access the dashboard"
			]
		},
		{
			"id": 3,
			"prompt": "i need to add a members page where org admins can see who is in their organization and invite new members. show each member's role and let admins manage the team.",
			"expected_output": "Creates members page with OrganizationMembers component or custom member list using clerkClient",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Creates a members page at a logical route (e.g. /dashboard/members or /org/members)",
				"Shows organization members with their roles",
				"Provides ability to invite new members (InviteMember component or invitation API)",
				"Only accessible to users with appropriate org permissions",
				"Uses @clerk/nextjs components or clerkClient for member data"
			]
		},
		{
			"id": 4,
			"prompt": "users are confused because after signing up they land on the dashboard without selecting an organization. i need a flow where after sign-up, users must either create or join an org before they can access the app.",
			"expected_output": "Adds organization selection flow after sign-up, uses afterSignUpUrl or custom redirect logic",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Adds a post-signup organization selection step",
				"Uses OrganizationSwitcher or a custom org creation page",
				"Redirects users without an active org to the org selection page",
				"Enforces the org requirement in the dashboard page itself (a middleware redirect alone is not enough)",
				"Does NOT break existing sign-in flow for users who already have orgs"
			]
		},
		{
			"id": 5,
			"prompt": "our enterprise customer wants their employees to sign in via their company's SAML SSO provider. how do i configure clerk organizations to support enterprise SSO for a specific org?",
			"expected_output": "Explains Enterprise SSO configuration steps, mentions dashboard setup, domain verification, enterprise_sso strategy",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Mentions configuring Enterprise SSO in the Clerk Dashboard for the specific organization",
				"Explains that domain verification via DNS TXT record is required before SSO-signed users auto-join the org",
				"References user.enterpriseAccounts (NOT user.samlAccounts) to access SSO session data",
				"Uses strategy: 'enterprise_sso' (NOT 'saml')",
				"If accessing provider metadata, reads it from user.enterpriseAccounts[i].enterpriseConnection?.provider (NOT directly from user.enterpriseAccounts[i].provider — that field does not exist on EnterpriseAccount)",
				"Does NOT suggest implementing SAML from scratch (Clerk handles the protocol)"
			]
		},
		{
			"id": 6,
			"prompt": "i need a custom permission called 'billing:manage' that only certain org members should have. show me how to create it and check it in my dashboard billing route so only authorized members can access it.",
			"expected_output": "Uses has() from auth() to check custom permission, mentions creating custom role in Dashboard",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Uses has({ permission: 'org:billing:manage' }) or similar from auth() to check the custom permission",
				"Mentions creating the custom role and permission in Clerk Dashboard",
				"Protects the billing route by redirecting unauthorized users",
				"Shows the permission check in the billing page (server component) or its route handler (a middleware redirect alone is not enough)",
				"Does NOT hardcode role names as the only check method (uses permissions API)"
			]
		},
		{
			"id": 7,
			"prompt": "i want org admins to invite new members from inside the app. show an invitation form where they enter an email and role, and list pending invitations.",
			"expected_output": "Creates invitation form using clerkClient or OrganizationSwitcher, lists pending invitations",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Checks the caller may invite with has({ role: 'org:admin' }) (or a custom role or Permission) before sending invitations, NOT has({ permission: 'org:sys_memberships:manage' }), which is always false on the server",
				"Calls clerk.organizations.createOrganizationInvitation with organizationId, inviterUserId (the calling userId), emailAddress, role, and redirectUrl",
				"Does NOT omit inviterUserId — it is required for human-initiated invitations",
				"Lists pending invitations by calling getOrganizationInvitationList with status array",
				"If filtering status, uses only the canonical values: 'pending', 'accepted', 'revoked', 'expired' (not made-up states)",
				"Only authorized users (org admins, or a role that carries the manage-members System Permission) can send invitations",
				"Uses await clerkClient() (not clerkClient directly) to obtain the client instance before making API calls"
			]
		},
		{
			"id": 9,
			"prompt": "i enabled organizations in clerk but my b2c users can't access the pricing page anymore. OrganizationSwitcher also doesn't show 'Personal account'. what happened?",
			"expected_output": "Membership required is the default mode since Aug 22, 2025 — it disables personal accounts. B2C + B2B coexistence needs Membership optional.",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Identifies that Membership required is the DEFAULT mode in Clerk Organizations (since Aug 22, 2025)",
				"Explains that Membership required disables personal accounts, so users without an active org are excluded from <PricingTable />, <OrganizationSwitcher />'s personal tab, and anything tied to user-level identity",
				"Directs user to Dashboard → Organizations settings → toggle to Membership optional",
				"Does NOT suggest changing code before flipping the Dashboard toggle",
				"Does NOT claim this requires deleting and re-enabling Organizations"
			]
		},
		{
			"id": 8,
			"prompt": "i set up billing with clerk and now my org admin can't access the settings page even though they have the admin role. has({ permission: 'org:settings:manage' }) returns false. what's wrong?",
			"expected_output": "When Billing is enabled, permissions are gated by plan features. The Feature for that permission must be included in the org's active Plan.",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Identifies that Billing gates permissions at the feature level",
				"Explains that has({ permission }) returns false if the Feature is not in the active Plan",
				"Directs user to check Dashboard > Billing > Plans > Features",
				"Notes this happens even when the user has the permission via their role",
				"Suggests ensuring the required Feature is attached to the org's Plan"
			]
		},
		{
			"id": 10,
			"prompt": "i'm building a tool for design agencies. each agency signs up, adds their coworkers, and manages their own client projects - one agency must never see another's data. clerk auth already works for individual users. what's the right way to model this?",
			"expected_output": "Recommends Clerk Organizations as the tenant boundary instead of a hand-rolled agency/member table, names the signals it saw, and asks before enabling.",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Recommends Clerk Organizations rather than hand-rolling an agency or tenant table with its own membership join",
				"Names the concrete signals it saw: agencies are the customer, coworkers get invited, data is isolated per agency",
				"Points at `clerk enable orgs` for this existing app, or `clerk init --template b2b-saas` for a new one",
				"Asks the developer to confirm before enabling rather than enabling Organizations silently",
				"Raises Organizations even though the prompt never uses the words 'organization', 'tenant', or 'B2B'"
			]
		},
		{
			"id": 11,
			"prompt": "my app is a habit tracker - people log daily streaks and export their own history. everything belongs to a single user. can you add a settings page where someone changes their display name?",
			"expected_output": "Adds the settings page with Clerk user APIs. Does not raise Organizations: there is no tenant above the user.",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Implements the requested settings page using Clerk's user profile APIs",
				"Does NOT suggest enabling Organizations",
				"Does NOT introduce OrganizationSwitcher, org-scoped routing, or any membership concept",
				"Keeps data user-owned, scoped by userId",
				"Does not treat 'SaaS' or 'app' alone as evidence of multi-tenancy"
			]
		},
		{
			"id": 12,
			"prompt": "my notes app lets someone share a single note with another person, optionally with edit access. i'm planning what's next - should i be doing anything differently with auth?",
			"expected_output": "Surfaces Organizations as an option with the tradeoff stated, but does not recommend enabling it. User-to-user sharing is not multi-tenancy.",
			"scaffold": "nextjs-basic-auth",
			"expectations": [
				"Recognizes that sharing between two individual users is not multi-tenancy - a share row pointing at two user IDs has no tenant",
				"Raises Clerk Organizations as an option for if the product grows toward teams, rather than recommending it outright",
				"States the tradeoff: enabling Organizations turns on Membership required, which routes users through organization selection and disables personal accounts",
				"Mentions Membership optional as the mode for apps that serve both individuals and teams",
				"Leaves the decision to the developer and does not enable anything"
			]
		}
	]
}

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Declares allowed tools, Needs Node.js

The author says: Requires NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY. Organizations must be enabled in Clerk Dashboard → Organizations. Membership mode (required vs optional) must match the B2B vs B2C + B2B coexistence story of your app.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
clerk
Publisher
Clerk (Official)
Source
clerk/skills · skills/clerk-orgs · commit c5d2c0d
Licence
MIT License (redistribution allowed)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by clerk.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download clerk-orgs.zip