# Deploy from your CI pipeline

What's new in Tray Helix · 29 September 2026 · https://helix.tray.ai/whats-new/deploy-from-ci/

Tray Helix can deploy from CI. In Helix CLI 1.3.0, helix ci init writes a GitHub Actions workflow that deploys the project on demand, on every merge to the default branch, or to staging on merge with production waiting for a reviewer in GitHub. CI signs in as a Tray API user through a TRAY_CLI_TOKEN secret, the job waits for the rollout and passes only when the new version is ready. Any other CI service can run the same deploy command.

**Available in:** Every Helix edition, with Helix CLI 1.3.0 or later.

Until now a Helix deploy ran from someone's machine, signed in as them. With Helix CLI 1.3.0 it can run from your CI pipeline instead. `helix ci init` writes the GitHub Actions workflow for you, CI signs in as a Tray API user, and `helix deploy --wait` keeps the job open until the new version is live, so the check on your commit tells you whether it shipped.

## An example

A team has a Helix project with a staging target and a production target, each deployed once by hand from a laptop. They want staging to follow `main` and production to ship only when someone signs it off. Here is the setup, start to finish.

### 1. Generate the workflows

From the project root, pick the CI service and how deploys should start:

```bash
helix ci init --provider github --strategy staging-on-merge
```

There are three setups. `manual-production`, the default, deploys production only when you start it. `production-on-merge` deploys production on every push to the default branch, and on demand. `staging-on-merge` deploys staging on every push and production on demand, behind an approval. Run `helix ci init` with no flags to choose in a prompt.

This team gets two files, `deploy-staging.yml` and `deploy-production.yml`. Before writing them, the command checks three things: that `helix.staging.config.ts` and `helix.production.config.ts` both exist, that each already has a `projectId` and `workspaceId`, and that the repo has a `package-lock.json` or `pnpm-lock.yaml`. It also pins the CLI in the workflow to the version of `@trayai/helix-sdk` the project uses, since the two are released together.

### 2. Give CI its own sign-in

CI needs a Tray API user, not a person's session. In Tray, go to **Account Settings**, then **Tokens**, then **Create API user**. Pick the workspace the project deploys to and the lowest workspace role that can deploy, then create a token with an expiry and copy it, because it is shown once. Check it works before you store it:

```bash
TRAY_CLI_TOKEN=<token> helix whoami
```

In GitHub, the staging-on-merge setup reads the secret from two environments, `Staging` and `Production`. Save the token as `TRAY_CLI_TOKEN` in each, and add required reviewers to `Production`.

### 3. Merge to main

The next push to the default branch runs `deploy-staging.yml`. Every generated workflow does the same four things: checks out the repo, sets up Node.js 24 and installs dependencies from the lockfile, installs the pinned Helix CLI, and runs:

```bash
helix deploy --config helix.staging.config.ts --wait
```

`--wait` keeps polling after the upload until Helix has finished rolling out. The job passes when the deployment is ready.

### 4. Ship to production

Start `deploy-production.yml` from the Actions tab, or from a terminal:

```bash
gh workflow run deploy-production.yml
```

GitHub holds the job until a reviewer on the `Production` environment approves it, then runs the same steps against `helix.production.config.ts`.

## What follows from how it works

- **The check on your commit is the truth.** A failed build fails the job and prints the build errors. If the rollout takes longer than 10 minutes, the job fails with a "still deploying" message, and `helix deployment wait <id>` picks up a deploy that is still going.
- **Merges close together don't trip over each other.** Only one deploy runs per target at a time, and a newer one never cancels a deploy that is already running.
- **Deploys are attributed to CI, not to whoever merged.** When `TRAY_CLI_TOKEN` is set, every `helix` command uses it and never writes a session to disk, so the same variable works on any machine.
- **Tests go before the deploy.** The generated file is yours. Add test or lint steps above the deploy step and a failure stops the deploy.
- **The approval is GitHub's.** The production reviewer is a GitHub environment rule, so who can approve is set in GitHub.

## What to watch for

**The token opens the whole workspace.** A Tray API user token is scoped to one workspace but reaches everything in it across Tray, including workflows and authentications. Treat it as a production credential: keep it in your CI secret store only, give the API user the lowest role that deploys, set an expiry, use a separate token per workspace, and delete the API user if the token leaks.

**Deploy by hand once first.** `helix ci init` refuses to write a workflow for a target with no `projectId` and `workspaceId` in its config. Deploy it once from your machine, or set both with `helix project set` and `helix workspace set`.

**Staging needs both config files.** The staging setup checks for `helix.staging.config.ts` and `helix.production.config.ts` before it writes anything, so a staging pipeline can never fall back to deploying production.

## Other CI services

`helix ci init` writes GitHub Actions workflows only. Any other CI service needs two commands, with `TRAY_CLI_TOKEN` supplied from its secret store:

```bash
npm install -g @trayai/helix-cli@<your @trayai/helix-sdk version>
helix deploy --config helix.production.config.ts --wait
```

## Links

- Release note: [Helix 1.3.0](https://helix.tray.ai/documentation/releases/130/)
- Docs: [Deploy from CI](https://helix.tray.ai/documentation/guides/continuous-deployment/)
- Docs: [Waiting for a deploy to finish](https://helix.tray.ai/documentation/reference/cli/deploy/)
- Docs: [Signing in with TRAY_CLI_TOKEN](https://helix.tray.ai/documentation/reference/cli/project/)

## Questions

### Which CI services does it work with?

helix ci init writes GitHub Actions workflows. Any other CI service can deploy by installing the Helix CLI at your Helix SDK version and running helix deploy with the wait option, with TRAY_CLI_TOKEN supplied from its secret store.

### Does a deploy from CI use someone's login?

No. CI signs in as a Tray API user through the TRAY_CLI_TOKEN secret, so the deploy is attributed to CI rather than to a person. When the variable is set, the CLI uses it for every command and saves nothing to disk.

### What happens when the build fails?

The deploy step exits with an error and prints the build errors, so the job fails. A red check means the new version did not ship.

### Can production deploys wait for an approval?

Yes, through GitHub. The staging-on-merge setup puts production in a GitHub environment, and adding required reviewers to it holds each production deploy until someone approves it in GitHub.

