























If you're building a SaaS product, multi-tenancy shouldn’t be an afterthought. Designing with multiple tenants in mind sets you up to scale effectively and securely.
But building multi-tenant logic from scratch can get complicated fast. You need to think through everything from how users join organizations to how sessions are scoped and how permissions are enforced across contexts.
That’s where Clerk comes in.
Clerk’s built-in support for isolating tenants within a single codebase simplifies the heavy lifting. Instead of wiring up custom logic, you can use Clerk’s drop-in UI components to get a multi-tenant foundation in place quickly, while still maintaining flexibility as your product grows.
In this guide, we’ll walk through how to use Clerk to build a complete multi-tenant experience into your app. Specifically, you’ll learn how to:
To demo this, you’ll learn how to add multi-tenancy features into a task manager called Kozi. At the moment, Kozi is feature complete for individual users, allowing them to add tasks and organize their tasks into projects.
Once the multi-tenancy features are added using Clerk, users will be able to create team workspaces and switch between them. Each workspace will have four distinct roles:
The app is built with Next.js, Clerk, Neon, and Prisma for the ORM.
If you want to follow along, clone the orgs-exp-start branch in the Kozi repo and follow the instructions in the README to get set up.
You’ll need the following before you get started:
Start by accessing your application in the Clerk dashboard. Select Configure from the top nav and then Settings under Organization management. Toggle the Enable organizations option to turn the feature on.
Once on, the view will update to present a number of new options. Here are a few notable ones:
Delete organization permission, allowing them to delete organizations. Turn this off if you want to allow users to create organizations but not delete them.
While we’re in the dashboard, create the roles and permissions by heading to Roles and Permissions, then select the Permissions tab. You’ll use the Create new permission button to create two permissions with the following values:
Next head back to the Roles tab and select the Create new role button to create the following role:
Next select both the Admin and Member roles and add the org:tasks:read and org:tasks:write permissions to enable those roles to use the new permissions.
Now that the Clerk application is configured, let’s move over to the code. The first change to make is to add the <OrganizationSwitcher /> component which is an all-in-one component that lets users create organizations, invite other members, and switch between the ones they have access to.
Open the project locally and update the Sidebar.tsx component to add the <OrganizationSwitcher /> component like so:
Now the bottom of the sidebar shows a “Personal account” button. This is the <OrganizationSwitcher /> component. By default every user has a personal account (meaning they do not have an organization active on their account), but clicking that button opens a menu allowing users to create new organizations:

With the <OrganizationSwitcher /> in place, let’s use it to create a new organization and invite others to it. Open the switcher and select Create Organization. This will bring up a modal where you can set the name of your new organization. I’ll create one called Frontiers:

After clicking Create organization, the form will ask for email addresses of anyone that should be invited to the organization, along with the role those users should be assigned:

Clerk handles the process of sending email invitations to those users. When the user clicks the Accept Invitation button in their email, they’ll be brought to the application where they will then be able to access that organization as well in the switcher.

At this point, Kozi permits users to switch their active organization, but the code still needs to be slightly modified to only return data relevant to that organization. As of now, the current user’s ID is used to filter data returned from the queries.
For example, the following code renders the Inbox page. It includes a query that returns tasks not associated to any projects. The auth helper function from Clerk is parsing the userId and setting that to ownerId which is in turn used in the query:
The auth function also returns an orgId if the user has an organization selected (it will return null otherwise) so we can modify the code to check for the orgId first and default back to the userId if it is not present:
The same change can be made to the page that renders each project:
And finally, all of the other queries stored in actions.ts:
The Sidebar.tsx renders a list of projects associated with the current user or organization, and while the getProjects function in the actions.ts file will fetch the correct list of projects, the Sidebar is a client component and we need a way for it to react to changes. Instead of using the auth helper function (which is a server-side function), we can use the useOrganization() helper to get details about the user’s active organization and react to changes with a useEffect.
Make the following changes to Sidebar.tsx to update it’s behavior:
With this change, the list of projects in the sidebar will react to changing between organizations.
Now that users can switch between organizations, you’ll need to handle the different roles assigned to each user. To make this as simple as possible, Clerk offers the has helper function which takes a role or permission as a parameter to check to see if the user in the current context has the proper role/permission.
Recall that we created the Reader role which should have read-only access to tasks. This role omits the orgs:tasks:write permission so we can conditionally render the components differently if the user’s role does not have this permission.
To prevent the user from creating tasks, edit CreateTaskInput.tsx as follows:
To make sure the user can’t edit tasks (including completing/uncompleting them), edit the TaskCard.tsx file:
The Sidebar should also be edited to prevent Reader users from seeing the option to add a project:
Now that the frontend is updated, you also need to modify any backend code to also check the user’s permissions for maximum security. Fortunately the has function works the same in server-side operations just like it does on the front end.
For any server action that makes changes to the database, you’ll use has to check the permissions like so:
Users with the Reader role in a specific organization should now only be able to see tasks in that organization, but not edit them. Furthermore if they switch to another organization where they have the Member role, they can add and edit tasks.
Using Verified Domains, you can also configure your application to automatically invite users to a specific organization if they sign in with an email address that matches a specific domain. This is extremely helpful for HR or IT teams who need to onboard users into an application. It avoids having them manually create a user record.
As an example, let’s say I want to automatically invite any user who signs in with an @clerk.dev domain name into the Frontiers organization. I’ll start by toggling Enable verified domains in the organizations settings page shown earlier. I’ll also enable Automatic invitation and Automatic suggestion to streamline the experience.

In Kozi, I’ll access the organization settings by opening the <OrganizationSwitcher /> and selecting Manage. In the modal, I can add a domain to the Verified domains list. I’ll be asked to verify ownership of the domain by entering my email address to receive a six digit code.

Now whenever somebody joins the app with an @clerk.dev email address, the <OrganizationSwitcher /> will automatically list the Frontiers organization as available for me to join and access.
Multi-tenancy is one of those architectural decisions that pays off early and compounds over time. Whether you're supporting teams, companies, or entire departments, having the right structure in place makes it easier to manage access, enforce security, and scale your product with confidence.
With Clerk, adding multi-tenant support doesn’t require reinventing your auth stack. You get drop-in UI components, APIs, and sensible defaults that help you stay focused on your product, not boilerplate.
As your app grows, so will the complexity of your users and their organizations. This guide gives you a solid foundation to handle that complexity with clarity.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。