What is multi-tenancy?

One instance serving several isolated customers or teams — what it gives you, what it does not, and how to tell whether you need it.

#What is multi-tenancy?

A tenant is one customer, client or team, with their own data, users and settings. Multi-tenancy is one running instance serving several of them at once, keeping each one's world entirely separate.

In EmuView a tenant is called a workspace, and the two words mean the same thing. Every instance already has one. Multi-tenancy is what happens when you add a second.

In the Emu Watch example that runs through the permission docs, a workspace is where the story ends: suppose the trust behind Sam's sightings log opens a second survey — an inland one, say — on the same instance. Each survey is its own world. Sam's roles, Priya's sightings, the Coastal Volunteers, every share and every never-rule belong to one workspace and never cross into the other; a member of one survey simply does not exist on the other. Everything on this page is about running several such worlds side by side — the walls between them, where the permission docs describe what happens inside one.

The alternative is running a separate instance per customer — separate databases, separate deployments, separate upgrades. That is simpler to reason about and far more expensive to operate. Multi-tenancy trades a little conceptual complexity for one thing to deploy, one thing to patch, and one bill.

#Do you actually need it?

Probably yes, if:

  • You are building a product that several organisations will use, and each must never see the others' data — an agency portal, a SaaS product, a platform for clubs or schools.
  • You resell the same application to multiple clients and want each on their own domain.
  • You run one organisation but need hard walls between divisions — separate users, separate content, separate branding — rather than the softer boundary that roles and permissions give you.

Probably not, if:

  • You have one organisation and one set of users. Roles and permissions already separate what people can see, and they are simpler.
  • You need per-customer views of shared data. Tenants cannot see each other at all, which is the wrong shape for that — use collections and access rules instead.
  • Your customers must be on genuinely separate infrastructure for a compliance reason. See what isolation you get below: this is application-level separation, not separate machines.

One workspace stays free. Multi-tenancy is dormant, not merely optional — an instance with a single workspace behaves exactly as it did before the feature existed. No configuration, no cost, no performance difference. Nothing wakes up until you give a second workspace an address of its own.

#What isolation you actually get

Worth being precise about, because "isolated" means different things to different buyers.

Separated per workspace:

Data Collections, records and files. Every query is scoped by workspace; nothing returns another's rows.
People Users, roles and permissions. An account belongs to one workspace.
Identity Sign-in configuration, and optionally each workspace's own OAuth application. A workspace on its own domain gets its own session signing key, so a session cannot be replayed against another.
Appearance Branding, theme and the public-facing pages.
Settings Nearly everything under Settings, including storage and email configuration.
Accounting Usage is metered per workspace, so you can bill or cap each one separately.

Shared, and deliberately so:

  • The deployment. One set of workers, one deploy, one upgrade. That is the point.
  • Infrastructure credentials. The instance's own storage and database credentials reach every workspace, because the instance is what serves them. A workspace can be given its own storage bucket — that buys a separate keyspace, separate lifecycle rules and separate billing, and it is a real boundary on data. It is not credential isolation, and this documentation will not pretend otherwise.
  • Anyone with operator access. A super administrator can reach every workspace. That is what makes the operator console possible.

If your requirement is "a breach of the instance must not reach customer B", multi-tenancy on one instance is the wrong tool, and so is every other multi-tenant product. Run separate instances.

#How the separation is enforced

One rule, and it is worth knowing because it is what the whole thing rests on: which workspace a request belongs to is derived from the session, never from the request.

A caller cannot select a workspace by sending a header, an Origin, a Referer, or a hostname. Those are things a client controls, and anything a client controls is something an attacker controls. The workspace comes from the authenticated session, and every query is scoped by it before it reaches the database.

Host-based routing looks like an exception and is not. A hostname decides which workspace's sign-in page you land on; it never decides which workspace an already-authenticated request reads from. That is also why the proxy has to sign the browser's hostname when it forwards it — an unsigned header would be exactly the client-controlled input this rule exists to reject.

#The controls you get

Each links to the detail.

Control What it does
Workspaces Create, suspend, release. Each gets its own slug and, optionally, its own domain. See Workspaces and tenants.
Domains A subdomain of your base domain, or a full custom domain. The first one you assign switches the whole instance to host-based routing.
Plans and entitlements Turn whole capabilities on or off per workspace — AI, automation flows, public publishing, outbound email, MCP, external databases, bring-your-own storage, PDF export, custom code. See below.
Usage limits Caps per metric, in three strengths: monitor records, soft flags the workspace as over, hard refuses the request. See Usage and limits.
Storage A dedicated bucket per workspace by default, or shared instance storage when asked for by name.
Databases Workspaces share the instance's database pool by default; one can be given its own.
Backups Scheduled per workspace, with their own retention.
Usage reporting Per-workspace metering, rollups and statements over a shared ledger.

#Entitlements are not permissions

The distinction catches people out, so it is worth ten seconds.

  • A permission answers "may this user do it?" — roles and access rules, inside a workspace. A workspace administrator can change these, and should be able to.
  • An entitlement answers "does this workspace's plan include it at all?" — set by you, the operator. A workspace administrator cannot change these, and that is the point.

Both must pass. An entitlement does not grant anything; it only withholds. A user still needs the permission, and no permission gets them past a withheld entitlement.

The reason the second control exists: a workspace administrator can already raise their own AI-token and email ceilings, and those spend against your Cloudflare account. Entitlements are the layer they cannot reach.

There is a third state besides granted and withheld — unknown, when the plan cannot be read. Every gate refuses on unknown rather than allowing, because a gate that opens on a database error is a gate an attacker opens by causing one. A workspace with no entitlements set is unrestricted, so nothing changes for an existing instance until you decide it should.

#The one thing to decide first

Whether workspaces get their own addresses. Everything else can be changed later; this one changes the behaviour of the entire instance the first time you use it.

While every workspace shares your instance's single address, requests cannot be told apart, so they all resolve to your primary workspace. Assign any workspace a domain and the instance switches to routing by hostname — each workspace answers only on its own address, and an unrecognised hostname is refused rather than quietly served your primary workspace's data.

That refusal is deliberate, and it is the reason the first domain assignment is gated behind a readiness check rather than a form. Workspaces and tenants covers what has to be true first and how to verify it.

Setup and npm run update now provision the secret that pairs the two workers for this, so on a current instance it is already done. If the readiness check says otherwise, that page explains how to finish it by hand.

#What it costs you

Honest accounting, because the answer is not "nothing":

  • One workspace: nothing. Genuinely dormant.
  • Several workspaces, one address: nothing. Routing stays off.
  • Host-based routing on: a wildcard DNS record and a route on your Cloudflare zone, which is a one-off. Once on, an unrecognised hostname is refused — so a DNS mistake becomes a visible error rather than a silent data leak, which is the trade you want but does mean DNS matters more.
  • Per-workspace storage or databases: real Cloudflare resources, on your bill.
  • Operational attention: you now have customers whose data lives together. The operator console, per-workspace usage and the audit plane exist to make that legible, but it is still more to watch than one workspace was.

#Where to go next