Multiple Organizations
What to do, in order, to serve more than one organization from one Deckyard instance, and what the organizations then share. Single-organization instances need nothing on this page.
1. Turn it on
Section titled “1. Turn it on”In .env:
MULTI_ORG_ENABLED=true# Recommended for a pre-provisioned instance: only instance admins create organizations.MULTI_ORG_USER_CREATE_ENABLED=falseRestart the server. MULTI_ORG_USER_CREATE_ENABLED defaults to true, which lets every signed-in user create an organization through POST /api/organizations (there is no button for it in the UI). On an instance where you create each organization yourself, turn it off: anyone who is not an instance admin then gets a 403.
An instance admin is a user with the admin role: AUTH_ADMIN_EMAIL, a member of one of OIDC_ADMIN_GROUPS, or someone given the role under Admin → Users. The instance role does not reach into an organization on its own; see step 5.
2. Name the default organization
Section titled “2. Name the default organization”Every instance has a default organization. In multi-organization mode it is the fallback: a new SSO user without an organization claim (step 6) gets their account and first membership there, and the first person in it becomes its owner.
Sign in once, as the operator, before anyone else. You become owner of the default organization; rename it in the organization profile to something neutral, such as the instance name or “Operator”. Keep customers out of it: it is the organization that cannot be deleted, and whoever lands there by accident sees everyone else who landed there.
3. Create the organizations
Section titled “3. Create the organizations”npm run org:create -- --slug acme --name "Acme" [--external-id <idp-org-id>] [--owner owner@acme.example]The command reads the same .env as the server, so run it on the host or in the container that runs Deckyard.
--slug: 2 to 63 characters, lowercase letters, digits and inner hyphens.--external-id: the organization’s ID in your identity provider, when SSO routes logins by organization (step 6). Must be unique on the instance.--owner: the organization’s first member, as owner. A person without an account gets one, homed in this organization. No invitation mail is sent: they sign in with SSO or a magic link, or you resend the invitation from Admin → Users.
Running it again with the same slug reports Already there and changes nothing. It refuses a rerun that disagrees with what is stored (another name, another external ID, an owner who is not the owner). Rename or rebind an existing organization in its profile or with PATCH /api/organizations/:id.
Two organizations with one member each:
npm run org:create -- --slug acme --name "Acme" --owner anna@acme.examplenpm run org:create -- --slug beta --name "Beta" --owner bram@beta.example4. Add members
Section titled “4. Add members”Everyone after the first comes in by invitation: the organization’s Users tab in settings, or POST /api/organizations/:id/members. An owner invites with any role, an admin only as member. An invitation to someone without an account creates it and mails a setup link; to someone who already has an account elsewhere on the instance, it adds a membership to that same account.
| Role | May |
|---|---|
member | Work in the organization; leave it. |
admin | Also: invite members, edit the profile, change member roles. |
owner | Also: invite admins and owners, hand the organization over, delete it. |
One person can hold memberships in several organizations; the user menu then lists them and switches between them.
5. Themes and organization settings
Section titled “5. Themes and organization settings”Each organization has its own default theme and its own set of themes members may pick, plus its other organization settings (designer rules, disabled slide types, feed metadata). Themes themselves belong to one organization.
Changing an organization’s admin settings takes both roles: instance admin, and admin or owner of that organization. The instance role alone is not enough; there is no impersonation. To set up a customer’s theme, the operator therefore needs a membership there: create the organization with yourself as --owner and invite the customer as owner afterwards, or let the customer’s owner invite you as admin. That membership is visible to the organization’s members, which is the point.
What is shared and what is not
Section titled “What is shared and what is not”| Instance-wide (one value for every organization) | Per organization |
|---|---|
Everything in .env: auth, SSO, mail transport, AI provider, feature flags | Presentations, slides, slide library, collections, tags, comments |
| App settings: supported languages, AI assistant, notifications, webhooks | Themes, and the default and enabled themes |
| Email templates and their settings: the operator sends the mail | Organization settings: designers, disabled slide types, feed metadata |
Instance admins (AUTH_ADMIN_EMAIL, OIDC_ADMIN_GROUPS, the admin role) | Members and their roles |
| Personal preferences: one set however many organizations a person joins | API keys; live sessions and analytics, through the deck they belong to |
6. Sign-in and where people land
Section titled “6. Sign-in and where people land”- SSO without an organization claim: a first login creates the account in the default organization (with
OIDC_AUTO_PROVISION=true, the default). Someone created withorg:create --owneror invited already has an account and a membership, and lands in that organization. - SSO with
OIDC_ORG_CLAIM: the named claim picks the organization whose external ID matches, and a first login there gets a membership in it. A missing or unknown claim refuses the login; nothing is created. Give each organization its external ID withorg:create --external-id. - Magic link and password: only for accounts that already exist. Someone without a membership gets one in their home organization.
Full SSO configuration: Authentication.
7. What changes when it is on
Section titled “7. What changes when it is on”- The RSS, Atom and JSON feeds are off (404, no autodiscovery links): there is no single organization to serve under one instance-wide URL.
- “Shared with me” crosses organizations: it is per person, so a deck someone shared with you shows up whichever organization you are in.
- Mail: invitations, setup links and notifications use the instance’s one mail transport and templates, whichever organization sends them.
AUTH_DEV_BYPASSdoes not work with it: the bypass pins the default organization, so test organization flows with a real login.
8. Check the result
Section titled “8. Check the result”npm run org:createagain with the same arguments printsAlready therefor each organization.- Each owner signs in and lands in their own organization; the organization profile shows its name, the Users tab shows one member.
- A deck made in
acmeis not visible frombeta: sign in as thebetaowner and open the home screen and the slide library. - As operator, switch into an organization you are a member of (user menu) and check its theme in a new deck.
GET /feed/rss.xml(andatom.xml,feed.json) answers 404.