Skip to content

Deploy with GitHub Actions

GitHub Actions is GitHub’s built-in automation system: it runs jobs in response to repository events, such as a push to your main branch. This page shows a complete, working setup that builds your app and deploys it to Comwit Cloud automatically every time you push.

The deploy itself is done by the comwit CLI, the same command-line tool you would run on your own machine. The only difference in CI is that you authenticate with a token stored as a repository secret instead of logging in through a browser.

The flow has three pieces:

  1. A cwt_ personal access token with the app:deploy scope, created in the console.
  2. That token stored as a GitHub repository secret, plus your project and app ids stored as repository variables.
  3. A workflow file (.github/workflows/deploy.yml) that builds the app, installs the CLI, authenticates, and runs comwit deploy.

In CI you can’t open a browser to log in, so you need a token that is created once and stored. Comwit Cloud uses cwt_ personal access tokens: scoped credentials tied to your user that can only do what their scopes allow and only touch projects you’re a member of.

  1. Open the console at https://cloud.comwit.io and go to API tokens at /tokens.

  2. Create a token and give it the app:deploy scope. That scope grants exactly what a deploy needs:

    ScopeGrants
    app:deployDeploy builds, roll back
  3. Copy the token value. The plaintext is shown once at creation — if you lose it, revoke it and create a new one.

Step 2 — Store the token and ids in GitHub

Section titled “Step 2 — Store the token and ids in GitHub”

GitHub separates secrets (encrypted, never printed in logs) from variables (plain config values). Put the token in a secret and the ids in variables.

In your repository, go to Settings → Secrets and variables → Actions, then:

  • Under Secrets, add COMWIT_TOKEN with your cwt_... value.
  • Under Variables, add COMWIT_PROJECT (your project id) and COMWIT_APP (your app id).

These names map straight onto how the workflow references them: ${{ secrets.COMWIT_TOKEN }}, ${{ vars.COMWIT_PROJECT }}, and ${{ vars.COMWIT_APP }}.

The workflow needs the comwit binary on the runner. The repository ships an install script, scripts/install-comwit.sh, that you can use locally; it works like this:

  • It first tries to download a GitHub release asset named like comwit_<os>_<arch>.tar.gz.

  • It supports a few environment overrides:

    install-comwit.sh environment overrides
    COMWIT_VERSION=v0.1.0 scripts/install-comwit.sh
    COMWIT_INSTALL_DIR=/usr/local/bin scripts/install-comwit.sh
    COMWIT_INSTALL_REPO=comwit/comwit-cloud scripts/install-comwit.sh
  • COMWIT_VERSION pins the release tag, COMWIT_INSTALL_DIR chooses where the binary lands, and COMWIT_INSTALL_REPO chooses which GitHub repo to pull the release from.

Create the file below at .github/workflows/deploy.yml in your application repository. It runs on every push to main, builds your app into ./dist, installs the CLI, authenticates with your token, and deploys.

.github/workflows/deploy.yml
name: Deploy to Comwit Cloud
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
# Project id is read by the CLI from COMWIT_PROJECT when --project is omitted;
# we pass it explicitly below as well.
env:
COMWIT_PROJECT: ${{ vars.COMWIT_PROJECT }}
steps:
# 1. Check out YOUR application source.
- name: Check out app
uses: actions/checkout@v4
# 2. Build your application into ./dist.
# Replace this with your real build. The output can be a built
# directory (the CLI packs it with `tar --zstd`) or a prebuilt
# `.tar.zst` package file.
- name: Build app
run: |
npm ci
npm run build
# Ensure your build output ends up in ./dist
# 3. Install the comwit CLI.
# Release binaries are not published yet, so build from source.
# (Replace this step with a release-asset download once
# comwit_<os>_<arch>.tar.gz assets exist.)
- name: Install comwit CLI
run: |
git clone --depth 1 https://github.com/comwit/comwit-cloud.git /tmp/comwit-cloud
(cd /tmp/comwit-cloud && just cli-build)
mkdir -p "$HOME/.local/bin"
cp /tmp/comwit-cloud/dist/comwit "$HOME/.local/bin/comwit"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
# 4. Authenticate with your cwt_ deploy token.
# `comwit login --token` stores the token in the CLI config file
# so later commands are authenticated.
- name: Authenticate
run: |
comwit login \
--token ${{ secrets.COMWIT_TOKEN }} \
--project ${{ vars.COMWIT_PROJECT }}
# 5. Deploy the build.
- name: Deploy
run: |
comwit deploy \
--project ${{ vars.COMWIT_PROJECT }} \
--app ${{ vars.COMWIT_APP }} \
--package ./dist
  • comwit login --token <cwt_...> --project <project-id> stores your cwt_ token (and a default project) in the CLI config file, ~/.config/comwit/config.json. After this, the CLI is authenticated for the rest of the job.
  • comwit deploy --project <project-id> --app <app-id> --package ./dist uploads your build and activates it. --package may be a built directory — which the CLI packs into a temporary .tar.zst using local tar --zstd — or an already-prebuilt .tar.zst file.

comwit deploy accepts a few extra flags you can add to the deploy step:

Deploy step with optional flags
- name: Deploy
run: |
comwit deploy \
--project ${{ vars.COMWIT_PROJECT }} \
--app ${{ vars.COMWIT_APP }} \
--package ./dist \
--host app.example.com \
--env-ref brrrd/env/app \
--max-concurrent-requests 100
  • --host binds one or more hostnames on deploy (comma-separated, e.g. a.example.com,b.example.com). See Custom hostnames.
  • --env-ref selects a runtime environment reference.
  • --max-concurrent-requests sets the runtime concurrency cap.

It’s worth being precise about what the token can and can’t do, because that’s what keeps the setup safe:

  • The cwt_ token authenticates every API call the CLI makes via Authorization: Bearer <token>.
  • It can only perform actions its scopes allow and can only touch projects you’re a member of. A deploy with an out-of-scope token or a project you’re not a member of returns HTTP 403.
  • The token is the only secret in the workflow. Keep it in secrets.COMWIT_TOKEN, never in a variable, log line, or committed file.

For the full token and scope model, see API authentication. For other CI systems, see Other CI providers.