Part 6: Stages and CI
Deploy another stage
Section titled “Deploy another stage”pnpm alchemy deploy --stage stagingbun alchemy deploy --stage stagingnpx alchemy deploy --stage stagingyarn alchemy deploy --stage stagingEach stage builds its own Golden snapshot and its own Worker, with its own Boat key, so changing the snapshot in one stage never reaches another. Without --stage, you deploy to live_$USER.
Stages share your Boat account. Sandboxes a stage’s Worker creates carry the stage as a label (alchemy.stage), so you can list one stage’s sandboxes without touching another’s:
const staging = yield* sandboxes.list({ labels: { "alchemy.stage": "staging" } });Destroying a stage deletes its snapshot and its Worker’s key, and leaves its sandboxes to stop on their timers.
Keep state in Cloudflare
Section titled “Keep state in Cloudflare”CI runs start from an empty disk, so store state where every run can read it:
{ providers: Layer.mergeAll(Cloudflare.providers(), Boat.providers()), state: Alchemy.localState(), state: Cloudflare.state(), },Store the key
Section titled “Store the key”Create a key in Boat’s dashboard (API Keys) with the admin preset: deploying creates the Worker’s own key. Add it to the repository’s secrets as BOAT_API_KEY. Alchemy reads it instead of a profile.
Deploy per pull request
Section titled “Deploy per pull request”name: Deployon: pull_request: push: branches: [main]
jobs: deploy: runs-on: ubuntu-latest env: BOAT_API_KEY: ${{ secrets.BOAT_API_KEY }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} STAGE: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.number) || 'prod' }} steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 - run: bun install - run: bun alchemy deploy --stage "$STAGE" --yesEach pull request gets its own stage, and so its own base: a pull request that changes Golden rebuilds it for that stage only. Boat has no keyless CI login, so the workflow uses the API key.
Clean up closed pull requests
Section titled “Clean up closed pull requests”name: Cleanupon: pull_request: types: [closed]
jobs: destroy: runs-on: ubuntu-latest env: BOAT_API_KEY: ${{ secrets.BOAT_API_KEY }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 - run: bun install - run: bun alchemy destroy --stage "pr-${{ github.event.number }}" --yesDestroying the stage deletes its snapshot and the Worker’s key.