Tenancy: single vs multi
The deployment shape — single-tenancy vs multi-tenancy — is declared by the active license, not by an env var. Same codebase, two faces, one source of truth.
TL;DR
- single tenancy — one customer org. The system auto-creates the default org + adds the local cluster as that org's edge on first license install. Admin/public pages (Public Edges / Global Marketplace / Public Registries) hide.
- multi tenancy — operator creates organizations through
the UI. Admin/public pages surface when the corresponding
MaxPublic*license cap is positive.
The distinction lives in the license's Binding.Tenancy
field — "single" or "multi".
Why two shapes
DT Edge Platform serves two distinct customer types:
- One customer who needs an ops console. Their team installs apps on a single (or small number) of clusters they own. Don't need orgs. Don't publish to a marketplace. Just want a UI around helm + observability + alarms.
- A SaaS operator running DT Edge Platform for many customer orgs. Multiple isolated tenants, each with their own edges + registries + marketplace + members. Public/admin surfaces optional based on contract.
Same product, same code path, two shapes. Sales / contracts decide which one a license is good for.
What changes between the two
The non-obvious thing: most of the product is identical. The core flow (install an app on an edge, manage releases, monitor with alarms) doesn't care about tenancy. What differs is the admin surface area.
| Surface | Single | Multi |
|---|---|---|
| Sidebar → Organizations | hidden (only one exists) | visible |
| Sidebar → Public Edges (admin) | hidden | visible if MaxPublicEdges > 0 |
| Sidebar → Global Registries | hidden | visible if MaxPublicRegistries > 0 |
| Sidebar → Global Marketplace | hidden | visible if MaxPublicMarketplacePackages > 0 |
| First-run experience | dashboard with the local edge ready to go | "create your first org" walkthrough |
| Org-scoped features (helm, alarms, audit log, ...) | identical | identical |
Why license-driven and not env-driven
There used to be a MODE=single|platform env var that did the
same thing. We dropped it. Reasons:
- Two sources of truth. Operators sometimes set
MODE=singlefor a license whose tenancy field saidmulti, or vice versa. There was no way to detect that mismatch from the running system; the UI showed one shape, the contract said another. - The contract should drive the shape. A customer paid for "single-tenant up to 25 nodes". The license already encodes that. Having the deployment also need a separate env var was redundant and error-prone.
- Tenancy swap should be a contract event. When a customer upgrades from single to multi, that's a re-issued license (with new caps). It shouldn't require a helm upgrade as well.
So today: one artifact (the license), one source of truth, no env var to misconfigure.
The trade-off: pre-license boot has clear semantics now — UI shows a "License Required" landing page, the API refuses mutations. There's no "we're in single mode but no license loaded" ambiguity.
What "the local cluster" means in single tenancy
When a single-tenancy license is uploaded, DT Edge Platform calls
bootstrap.EnsureSingleTenancy:
- Creates a default org named after the license's customer name
- Adds the cluster DT Edge Platform is running in as that org's edge
instance — the kubeconfig comes from
rest.InClusterConfig()which works inside any k8s pod - Grants the super-admin
org:adminon the default org
Idempotent — license renewal is a no-op for the bootstrap (the org + edge are already there).
The local cluster is just like any other edge. You can register other edges alongside it (same org), install apps on either, remove the local one if you ever migrate DT Edge Platform somewhere else.
Switching tenancy
Re-issue the license with a different Binding.Tenancy value
and upload it. Effects:
- single → multi — admin/public pages start surfacing per
the new license's
MaxPublic*caps. Existing default org + local edge stay in place; you can keep them or replace them. - multi → single — admin/public pages hide. Existing orgs stay in the database; the bootstrap is idempotent and doesn't delete anything. Typically you only do this when consolidating to one org anyway.
It's rare; usually reflects a contract change.
What stays multi-tenant in single tenancy
The codebase is fundamentally multi-tenant. Single tenancy is a special case of multi tenancy where N=1.
That means:
- Every row still has
org_id. The default org is just one of (potentially) many. - Casbin still runs. The default org has its own roles, members, permissions.
- Admin / super-admin distinction still exists. The super-admin
isn't automatically a member of the default org — they get an
explicit
org:admingrant during bootstrap.
If a single-tenancy install ever needs to "grow into" multi-tenancy (e.g. a small team becomes a SaaS), it's a license re-issue + uploading the new JWT. No data migration.
See also
- License states — what
tenancy: ""means before a license loads - What is DT Edge Platform? — the broader picture
- Backend docs: Concept → Tenancy
- ADR-008: License-driven tenancy