# Environments

https://exo.now/docs/shipping/environments

> Preview, Staging, Release Candidate, and Production — one purpose, one artifact, and one approval boundary each.



Source: [managed environment lifecycle](../../../docs/environment-lifecycle.md). These are
deployment stages, not product lifecycle labels. A project can be in private beta while running a
production environment, and setting `project.lifecycle` to `stable` never authorizes a deployment.

## Canonical names [#canonical-names]

| Stage             | Persistent   | Default Git source                 | Release channel |
| ----------------- | ------------ | ---------------------------------- | --------------- |
| Preview           | No, optional | Remote-canary or pull-request head | Internal        |
| Staging           | Yes          | `staging`                          | Internal        |
| Release Candidate | Yes          | `release`                          | Candidate       |
| Production        | Yes          | `main`                             | Stable          |

Human-readable names follow the pattern `{Project} · Staging`. Provider names and generated URLs
are separate operational metadata.

## Preview (optional) [#preview-optional]

An ephemeral, server-backed environment for the exact pushed canary or pull-request head. It
inherits staging configuration, uses isolated data when mutations are possible, and is removed
when the pull request closes. It must never inherit production customer data or credentials.

## Staging [#staging]

The persistent integration environment, showing the combined state of upcoming work.

* **Source:** `staging`. Agents never develop directly on it; they integrate validated commits from
  canary branches.
* **Deployment:** every update automatically deploys after the projects.dev credential and spend
  gate passes. No owner approval sits between the branch update and the deployment.
* **Access:** private by default, routed by the [staging topology](./staging.mdx).
* **Optional services:** integrations such as outbound email may stay disabled when
  staging-specific credentials are absent. Health and read-only routes must keep working.

## Release Candidate [#release-candidate]

The production-like environment for the exact version proposed for the next release. It accepts
fixes only after the candidate is cut, promotes the same verified build onward, and applies to any
release worth freezing, including patches. Creating or replacing it needs explicit owner
direction.

## Production [#production]

The live environment. `stable` is its release channel label, not a name for the environment. It
deploys only the approved Release Candidate artifact after explicit owner approval on the
`release` → `main` pull request.

## Promotion rules [#promotion-rules]

1. No stage implies approval for the next stage.
2. The deployed commit, build checksum, configuration class, and approval evidence are recorded at
   every promotion.
3. Secrets and persistent data are isolated by stage. Production values never flow backward.
4. Rollback promotes a previously verified artifact or reverts through the normal approval path.
5. Provider state is observed separately from `project.yaml`. Drift does not rewrite the contract.
6. A provider capability is not configured until its environment, URL, access boundary, and
   lifecycle behavior are verified live.
7. Every deployment needs fresh projects.dev evidence: credential inventory checked, billing
   visible, a spend limit configured, and no limit exceeded.
8. Staging integration is not an approval gate. Domain, billing, destructive data, credential, and
   production migration actions keep their own approvals.
9. Ordinary staging code delivery is automatic. Changing the provider binding, credentials,
   domain, billing configuration, or persistent data is a separately authorized mutation.
10. Apps stage under `staging.exo.now` and Construct Pages under `staging.construct.page`. An App's
    production domain never owns its staging hostname.
