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

# Versioning and releases

> Two packages, one version, pinned exactly per site. The shared API and database move for everyone at once, so they only ever change additively.

## Four surfaces, one version number

| Surface                               | Ships                                                        | Pace                                           |
| ------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------- |
| `@sp-stage/sdk` and `@sp-stage/admin` | Published to the private registry, then a site bumps its pin | Versioned, per site                            |
| The shared API                        | Deploys on merge                                             | Latest, for every site at once                 |
| The database schema                   | Migrations applied per release                               | Latest, for every site at once                 |
| The site's own code                   | The site's own repository                                    | Per site, compiled against its pinned packages |

A pin protects a site from **package** changes only. The API and database move under every site instantly, which is why the compatibility rule exists.

## The two standing rules

<Steps>
  <Step title="API and database changes are additive and backward-compatible">
    After any rollback an old package talks to the newest API and schema, so the newest must keep working for the oldest pinned version in the fleet.
  </Step>

  <Step title="Release small and often">
    A big batched release destroys rollback granularity: rolling back past a two-week batch loses two weeks of fixes, not one day's.
  </Step>
</Steps>

## Expand, migrate, contract

* **Expand** freely: tables, nullable or defaulted columns, new routes, optional parameters, new response fields. Old clients ignore what they do not know.
* **Migrate**: release the package version that uses the new thing; roll sites forward.
* **Contract** only in a breaking release, and only once every site is at or above the version that stopped depending on the old shape.

Never in one step: renames (add the new, dual-read, drop the old later), narrowing a type, making an optional parameter required, repurposing a field.

## The release flow

1. A change to the packages carries a changeset. Its first paragraph is the changelog post.
2. Merging to main ships nothing. A "Version Packages" pull request accumulates pending changesets.
3. Merging that pull request publishes. Nothing deploys to any site.
4. Each site adopts a version deliberately: a bump pull request in its own repository, or an explicit version move for a rollback. Merging it is that site's go-live.

While versions are `0.x`, a **minor** bump means breaking and a **patch** means everything else. A breaking changeset carries its migration note right then.

## Rollback

Edit the site's pin back and redeploy. Deployed sites are never touched by any of this machinery; only the next build changes. A rolled-back site is an old package on the newest API, protected only by the compatibility rule. Rollback is a tourniquet, not a destination.
