> ## Documentation Index
> Fetch the complete documentation index at: https://docs.brussle.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-tenant platforms

> One namespace per tenant: isolated, independently billed, and free when idle.

If you serve tenants and want judgments per tenant, give each tenant its own namespace. Namespaces are the unit of scale, caching and billing. A platform with 50,000 tenants has 50,000 namespaces and pays nothing for the ones nobody touches.

## What tenants cost

Each tenant's usage is billed like any other: judgments, storage, writes and queries. On top of that, platforms pay a small **tenant fee** per active tenant namespace each [billing period](/pricing#billing-periods), past the ones their plan includes (25 on Developer and Team, 100 on Scale). A namespace is active in a period if at least one judgment in it was billed in that period. One you only write to or read from, and `default/quickstart`, never count.

The fee is \$2 per active namespace up to the 1,000th, \$1 up to the 10,000th and \$0.50 above that, counted from your first, with your plan's included namespaces off the bottom. It's added on top of your plan's minimum, not counted toward it, and it stays out of each namespace's budget.

For example, a platform on Team with 5,000 tenant namespaces, 2,000 of them judged this billing period, and 72M judgments:

| Line | Cost |
| - | - |
| Judgments, 72M at \$0.25 per 1,000 | \$18,000.00 |
| Team minimum (\$499) | already met by usage |
| Active tenant namespaces: 2,000 (25 included): 975 × \$2 + 1,000 × \$1 | \$2,950.00 |
| **Invoice** | **\$20,950.00** |

The 3,000 tenants nobody's judgments touched that period cost nothing but their storage. The same platform on Scale would pay 900 × \$2 + 1,000 × \$1 = \$2,800 of fee, with 100 included. See [tenant namespaces](/pricing#tenant-namespaces) for the bands and how the fee is charged as it grows.

### Staging tenants are not counted

If you mirror your tenants in staging (`acme/staging/tenant_123` beside `acme/prod/tenant_123`), mark `acme/staging/` as **non-production**. Admins and owners do it in the dashboard, under **Settings → Non-production prefixes**, or with the API and a `read_write` key scoped to your whole organization. It's off by default.

A namespace then counts toward the tenant fee only if it had a billed judgment in an hour it wasn't under a marked prefix. Marking takes effect from the next whole UTC hour, so mark the prefix before staging's first judgment: marking it late in a billing period exempts nothing already judged. Judging under a marked prefix is still billed as usage, like any other judging. Its tenants also stay out of production's [pooled calibration](/guides/templates#calibration-across-tenants).

For example, a platform on Team with 1,600 production tenants judged this billing period, a staging mirror of each judged too, and 75M judgments between them:

| Line | Cost |
| - | - |
| Judgments, 75M (72M production, 3M staging) at \$0.25 per 1,000 | \$18,750.00 |
| Team minimum (\$499) | already met by usage |
| Active tenant namespaces: 1,600 (25 included; 1,600 non-production not counted): 975 × \$2 + 600 × \$1 | \$2,550.00 |
| **Invoice** | **\$21,300.00** |

Unmarked, all 3,200 would count: 975 × \$2 + 2,200 × \$1 = \$4,150 of fee. See [staging and test environments](/guides/staging-environments) for the setting's API and how to promote a change from staging to production.

## Name namespaces as a hierarchy

Use the hierarchy for environment and tenant: `acme/prod/tenant_123`, `acme/staging/tenant_123`. Listing (`GET /namespaces?prefix=acme/prod/`) and key scoping work on prefixes. Deleting works on one namespace at a time. There is no project object: the hierarchy is the project structure. See [tenants and environments](/concepts/namespaces#tenants-and-environments).

## Scope keys by prefix or namespace

An API key can be restricted to a namespace prefix, or to one namespace, and a role. Give each backend service only what it needs:

| Key | Can do |
| - | - |
| `read_write` scoped to `acme/prod/*` | Everything in production |
| `read_only` scoped to `acme/prod/*` | Reads and queries only |
| `read_write` scoped to `acme/staging/*` | Nothing in production |
| `read_write` scoped to `acme/prod/tenant_123` | That one tenant, and nothing else |

A prefix stops at a `/`. `acme/prod/tenant_1*` covers `acme/prod/tenant_1` and everything under `acme/prod/tenant_1/`, never `acme/prod/tenant_12`. For a tenant's own key, scope it to the tenant's namespace.

A scope can name namespaces that do not exist yet. Create a key for `team-a/*` or for `acme/prod/tenant_456` before its first write, and hand it over when you provision the team or tenant: the key's first write or judgment creates the namespace.

Keys belong to your organization, not to people. Create them on the dashboard's Keys page, which asks for each key's role rather than picking one for you and shows the role and scope with the new key.

## Define judgments once for every tenant

Create the judgment on a prefix, such as `acme/prod/*`, and every namespace under it inherits it, including tenants created later. A tenant can override its thresholds and freshness policy, or detach the judgment into its own copy. See [templates](/guides/templates).

Calibration learns across tenants. Outcomes from every tenant are pooled into one fit per template version, so a tenant you onboard today gets calibrated answers from its first write, from what earlier tenants taught the pool. On Scale, a tenant with enough outcomes of its own also grows its own fit, weighted more heavily as its own outcomes grow, and used only when it beats the pool on that tenant's held-out outcomes, and the tenant keeps following the template. See [each tenant grows its own fit](/guides/templates#each-tenant-grows-its-own-fit-scale).

You can still define a judgment on each tenant's namespace instead, with one call per tenant, usually made when the tenant is provisioned:

```python theme={"theme":{"light":"css-variables","dark":"css-variables"}}
for tenant in new_tenants:
    db.namespace(f"acme/prod/{tenant.id}").judgments.create(**needs_escalation_definition)
```

Each tenant then has its own definition and versions.

## Get told when documents change in any tenant

A [subscription](/concepts/subscriptions) on the same prefix tells you when a document in any tenant starts or stops matching a filter, without polling each tenant:

```python theme={"theme":{"light":"css-variables","dark":"css-variables"}}
db.namespace("acme/prod/*").subscriptions.create(
    name="escalations",
    filters=("answers.needs_escalation.thresholds.escalate", "Eq", True),
    events=["entered", "exited"],
    endpoint=prod_endpoint["id"],
)
```

* Every event names the tenant in `namespace`, so one receiver routes events for all your tenants without a lookup. `subscription.defined_on` says the event came from the template.
* Each tenant keeps its own matching set and starts at its next change, so idle tenants cost nothing, and tenants created later are covered.
* Tenants can't opt out or change it. To leave one out, add a condition on `id` or an attribute to the filter.
* Staging works the same way. Put a subscription on `acme/staging/*` with an endpoint scoped to `acme/staging/`, and staging events reach your staging receiver only. An endpoint must cover the whole prefix of the subscriptions that send to it.
* A tenant creates a subscription only while it has fewer than 100, counting the template's; subscriptions the template gains later can take it past 100. See [templates](/guides/templates#subscriptions-for-every-tenant).

## Budgets per tenant

Each namespace can carry its own compute budget for each [billing period](/pricing#billing-periods), so one tenant's burst cannot run up your bill: judging is priced before each request to the engine, and stops before the budget would be passed. When a tenant's namespace reaches its budget, its changed answers go `stale`, documents never judged read `unavailable`, and its writes continue, or, with `"on_exceeded": "reject"`, its writes are refused with `budget_exceeded`.

## Pinning and warming

Idle namespaces fall out of cache. The first query after that is cold and takes hundreds of milliseconds. Two tools help:

* **Warm** a namespace when you know a session is starting: `POST /namespaces/{ns}/warm` (`ns.warm()`). It is free and best-effort.
* **Pin** a namespace that must never be cold: `PATCH /namespaces/{ns}` with `{"pinned": true}`. It stays resident in cache and is billed per GiB-month as a [pinned namespace](/pricing#usage).


## Related topics

- [Subscriptions](/concepts/subscriptions.md)
- [Import existing data](/guides/import-existing-data.md)
- [Summarize every tenant](/guides/tenant-summary.md)
- [Relations](/concepts/relations.md)
- [Pricing](/pricing.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.