> ## 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.

# Staging and test environments

> Staging as a prefix in your production organization: its own key and budgets, left out of the tenant fee and production calibration.

Your staging environment is namespaces under a staging prefix, in the same organization as production. It gets its own key, its own budgets and, if you use them, its own [templates](/guides/templates). Judging there is billed like judging in production. Mark the prefix non-production, and its tenants add nothing to the [tenant fee](/pricing#tenant-namespaces) or to production's calibration.

`default/quickstart` is not a staging environment. It is a free place to try things, with a small limit each billing period ([pricing](/pricing#quickstart)). Point your staging deployment at a prefix of its own.

## A layout

Mirror production's names under another environment prefix (see [tenants and environments](/concepts/namespaces#tenants-and-environments)):

| | Production | Staging |
| - | - | - |
| Tenant namespaces | `acme/prod/tenant_123`, `acme/prod/tenant_456` | `acme/staging/tenant_123`, `acme/staging/tenant_456` |
| Template | `acme/prod/*` | `acme/staging/*` |
| Key | `read_write` scoped to `acme/prod/*` | `read_write` scoped to `acme/staging/*` |
| Budget | per namespace, sized for the tenant | per namespace, small: `{"compute_usd_per_month": 20, "on_exceeded": "pause"}` |
| Non-production | no | `acme/staging/` marked |

* **The key.** Give your staging deployment only the `acme/staging/*` key. It can't read or change anything in production, and it can't mark or unmark prefixes. Create keys on the dashboard's Keys page. A scope can name a prefix before anything under it exists.
* **The template.** Define staging's judgments on `acme/staging/*`, so every staging tenant has them, as production's are on `acme/prod/*`. Templates need the Team plan, in staging as in production.
* **The budget.** A budget is a [namespace setting](/concepts/namespaces#settings); there is none on a prefix. A namespace exists from its first write, so set the budget with `PATCH /namespaces/{ns}` (`ns.update(budget=...)`) right after each staging tenant's first write; before it, the call returns `not_found`. With `pause`, a staging tenant that reaches its budget stops judging: changed answers read `stale`, documents never judged read `unavailable`, and writes continue.

## Mark the prefix non-production

Admins and owners mark prefixes in the dashboard, under **Settings → Non-production prefixes**; every member can see the list. With the API, marking and unmarking take a `read_write` key scoped to your whole organization (`*`), and any key of the organization can list:

<CodeGroup>
  ```ts TypeScript theme={"theme":{"light":"css-variables","dark":"css-variables"}}
  await db.nonproductionPrefixes.mark("acme/staging/");
  const { prefixes } = await db.nonproductionPrefixes.list();
  await db.nonproductionPrefixes.unmark("acme/staging/");
  ```

  ```python Python theme={"theme":{"light":"css-variables","dark":"css-variables"}}
  db.nonproduction_prefixes.mark("acme/staging/")
  prefixes = db.nonproduction_prefixes.list()["prefixes"]
  db.nonproduction_prefixes.unmark("acme/staging/")
  ```
</CodeGroup>

These are `PUT /nonproduction-prefixes/acme%2Fstaging%2F`, `GET /nonproduction-prefixes` and `DELETE /nonproduction-prefixes/acme%2Fstaging%2F`. All three return the list:

```json theme={"theme":{"light":"css-variables","dark":"css-variables"}}
{"prefixes": [{"prefix": "acme/staging/", "marked_at": "2026-09-27T14:05:12Z"}]}
```

* A prefix is namespace characters ending in `/`. `acme/staging/*` is accepted and stored as `acme/staging/`. It can't be the whole organization.
* It needs no namespaces yet. Mark it before staging's first judgment.
* Up to 20 prefixes are marked at once; marking a 21st returns `conflict`. Marking a marked prefix, or unmarking one that isn't marked, changes nothing.
* Each marking counts while its prefix is marked and for 90 days after it is unmarked, and at most 100 count at once: a mark past that returns `conflict`. Unmarking is never refused.
* Each change is in your audit log as `org.nonproduction`.

### What it changes

* **The tenant fee.** A namespace counts 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, and unmarking from the start of the hour it happens in. So marking late in a billing period exempts nothing already judged. The invoice line says what was left out: "Active tenant namespaces: 1,600 (25 included; 1,600 non-production not counted)". See [staging tenants are not counted](/guides/multi-tenant-platforms#staging-tenants-are-not-counted) for a whole bill.
* **Calibration.** A template's calibration pool leaves out tenants under a marked prefix: their outcomes shape neither its pooled calibration nor the prior that tenants' [own fits](/guides/templates#each-tenant-grows-its-own-fit-scale) shrink toward. They read the pool, and get no fit of their own; their [calibration report](/guides/templates#reports) says `tenant.reason: "non_production"`. This matters when one template covers both environments, such as `acme/*`. A template under the marked prefix, such as `acme/staging/*`, pools its staging tenants among themselves, so staging is calibrated like production without touching it.
* **Nothing else.** Judging, storage, writes and queries under a marked prefix are billed as usual, and shadow reports sample its tenants as usual.

## Promote a change from staging to production

A judgment change reaches production the way it reached staging: you create the same definition on the production prefix, and a [shadow report](/guides/measure-improve-tune#change-a-question-safely-with-a-shadow-report) on production's own documents decides the switch. There is no route that copies a judgment from one prefix to another, so keep the definition in your code.

1. **In staging**, create the new version on `acme/staging/*` with the staging key, by posting the definition again under the same name. It stays inactive.
2. **Activate it there.** You get one shadow job, sampled across the staging tenants. Read its report, then confirm it to switch every staging tenant, and test your staging deployment against it.
3. **In production**, create the same definition on `acme/prod/*` with the production key. Versions are numbered per template, so its number there can differ.
4. **Activate it on `acme/prod/*`** and read that shadow report, sampled across production tenants. Confirm it to switch every production tenant, or cancel it to leave production as it was.

<CodeGroup>
  ```ts TypeScript theme={"theme":{"light":"css-variables","dark":"css-variables"}}
  // db is a client with the acme/prod/* key.
  const prod = db.namespace("acme/prod/*");
  const { version } = await prod.judgments.create(needsEscalation); // the definition staging tested
  const activation = await prod.judgments.activate("needs_escalation", { version });
  if ("id" in activation) {
    // Read (await db.jobs.get(activation.id)).report once it is filled in, then:
    await db.jobs.confirm(activation.id);
  }
  ```

  ```python Python theme={"theme":{"light":"css-variables","dark":"css-variables"}}
  # db is a client with the acme/prod/* key.
  prod = db.namespace("acme/prod/*")
  created = prod.judgments.create(**needs_escalation)  # the definition staging tested
  assert "version" in created  # a definition with no related documents is created at once
  activation = prod.judgments.activate("needs_escalation", version=created["version"])
  if "id" in activation:
      # Read db.jobs.get(activation["id"])["report"] once it is filled in, then:
      db.jobs.confirm(activation["id"])
  ```
</CodeGroup>

Don't `force` the production activation. Staging's report was measured on staging's documents, and production's can shift differently. Shadow reports are free on both.

## Keep staging data synthetic

Staging documents are judged like production's, so the engine's provider sees them: each [engine's page](/engines/index) names who handles your data. Use synthetic or scrubbed records in staging where you can, rather than copies of production data.


## Related topics

- [Multi-tenant platforms](/guides/multi-tenant-platforms.md)
- [Namespaces](/concepts/namespaces.md)
- [Quickstart](/quickstart.md)
- [Receive webhooks](/guides/webhooks.md)
- [webhook.test](/api-reference/webhooks/webhooktest.md)


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