Deploying from CI
CI deploys with a deploy token: scoped to one project (optionally one environment), expiring, revocable, audited. It may deploy and read that project, nothing else: no secrets, no tokens, no other projects. Any CI works the same way; GitHub Actions is the example below.
1. Create a deploy token
scaledbox tokens create ci-prod --env prod # --days 90 by default; without --env: every environment
The token (sbx_…) is shown once. Store it as a CI secret, e.g. SCALEDBOX_DEPLOY_TOKEN in the
repository's GitHub Actions secrets. Rotate it before it expires: create a new one, update the secret,
then revoke the old one (scaledbox tokens list, scaledbox tokens revoke <id>).
2. Build your services' modules
Each service's dir (in scaledbox.toml) must hold its box.toml and its built JavaScript modules
(ES modules; TypeScript and JSX are bundled by you), each module's source map beside it, and its
assets directory its static files. Any bundler does: esbuild, for example.
- uses: actions/setup-node@<pinned>
with:
node-version: 24
- run: npm ci
- run: npx esbuild src/index.ts --bundle --format=esm --platform=neutral --sourcemap --outfile=dist/web/index.js
- run: cp box.toml dist/web/
Nothing is built on scaledbox and no image is pushed: the deploy sends the files.
3. Deploy in the workflow
The CLI reads SCALEDBOX_TOKEN instead of a sign-in, so a workflow that installs it
(curl -fsSL https://scaledbox.dev/install.sh | sh) deploys with the token. It sends scaledbox.toml
and each service's files by their SHA-256, uploads only those scaledbox lacks, and waits for the
release:
- name: Deploy to scaledbox
env:
SCALEDBOX_TOKEN: ${{ secrets.SCALEDBOX_DEPLOY_TOKEN }}
run: |
curl -fsSL https://scaledbox.dev/install.sh | sh
~/.local/bin/scaledbox deploy --env prod
A failed release leaves the previous one running; the step fails with the reason (e.g. the release handler's error, or a health path that didn't answer).
Without the CLI, the API takes the same three steps: POST /v1/projects/<project>/environments/<env>/deploys with scaledbox.toml and each service's files'
hashes (it answers the missing ones, in buckets), POST .../deploys/<id>/files with each bucket
(multipart, a part per file named by its hash), then POST .../deploys/<id>/finish, which answers
the release to poll at GET .../releases/<number> until it is live or failed.
A pull request's workflow deploys its preview the same way (--env pr-<number> --preview) and deletes
it when the pull request closes (scaledbox environments delete --env pr-<number>).