GitHub Action
You can use our CLI inside a GitHub action as any other CLI tool.
We also provide our own GitHub Action, available for free on GitHub Marketplace.
The examples below use quaveone/quaveone-deploy-action@main, which tracks the latest Quave ONE deploy action.
Tip: You can switch between CLI and GitHub deployment methods at any time from your App Settings page. See Switching Deployment Method for details.
Let's understand how you can use our GitHub Action to deploy your app.
Deploying using our GitHub Action
To deploy your app on every push to main, create a yaml file at .github/workflows/quaveone-deploy.yml with the following content:
name: Deploy
on:
push:
branches: ['main']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Deploy
uses: quaveone/quaveone-deploy-action@main
with:
user-token: ${{ secrets.QUAVEONE_USER_TOKEN }}
env: "customer-my-app"
That's it. Every push to main will trigger a deployment.
The action is always non-interactive. It passes user-token or env-token inputs into the CLI as environment variables and does not use quaveone login or local CLI config. Use local CLI login for your laptop; use GitHub secrets for Actions.
Fun fact: we use our GitHub Action to deploy our docs to Quave ONE (yes, this website you are reading right now).
Available Configurations
| Parameter | Required | Description |
|---|---|---|
env | Normal deploy | Environment name for a normal deployment. For preview deletion, it must be the exact CLI preview name printed by an earlier preview deployment. |
user-token | No | Token to authenticate the user. Get this token at app.quave.cloud/profile. We recommend creating a secret called QUAVEONE_USER_TOKEN. |
env-token | No | Token to authenticate the app environment. Get this token in the environment settings tab. We recommend creating a secret called QUAVEONE_ENV_TOKEN. |
dir | No | Directory to use as the source code root for deployment. |
image | No | Docker image name to deploy (for pre-built image deployments). |
app | No | Name of the app in which the environment will be created or updated. |
copy-env-vars-from | No | Name of the environment from which only env vars will be copied to the new environment. It does not clone resources, security settings, startup settings, or cleanup TTL. |
preview | No | When "true", run the one-command quaveone preview deploy flow instead of quaveone deploy. |
from | If preview | Source environment identifier forwarded to quaveone preview deploy --from. |
ttl-hours | If preview | Absolute preview TTL in hours. |
idle-hours | No | Optional idle timeout in hours for preview cleanup. |
commit-sha | No | Source commit SHA stored in preview metadata. |
delete-on-pr-close | No | When "true" and the pull request is closed, run quaveone preview delete --env. env must be the exact CLI preview name printed by an earlier preview deployment. |
prevent-destroy | No | When "true", create the preview with Prevent destroy enabled. |
api-cli-uri | No | Custom API URL — only for clients using Quave ONE Connect Full Private. |
cli-extra-args | No | Extra arguments to pass to the CLI. Example: --command "bun run start:worker" or --wait --wait-timeout-seconds 1800. Configure application environment variables persistently through Quave ONE before deploying. |
You can also use
env-token: In Quave ONE web app you get this token for your app env at its settings tab. We recommend you to create a secret in your GitHub project underSettings > Security section > Secrets and variables > ActionscalledQUAVEONE_ENV_TOKEN.
Automatic branch previews
Use a GitHub Actions workflow with the Quave ONE CLI to create or reuse a temporary preview for every pushed branch except your main deployment branches. preview deploy clones the preview-safe configuration from the source environment, uploads the checked-out source, and deploys it in one CLI command. Quave ONE cleans up the preview after its TTL or idle window.
Create .github/workflows/quaveone-branch-preview.yml:
name: Quave ONE branch preview
on:
push:
branches-ignore:
- main
- master
- production
- staging
jobs:
branch-preview:
runs-on: ubuntu-latest
container:
image: quaveone/quaveone-cli:latest
env:
QUAVEONE_USER_TOKEN: ${{ secrets.QUAVEONE_USER_TOKEN }}
steps:
- uses: actions/checkout@v7
- name: Deploy branch preview
run: |
quaveone preview deploy \
--app "acme-web" \
--from "acme-web-staging" \
--branch "$GITHUB_REF_NAME" \
--ttl-hours 72 \
--idle-hours 8 \
--dir "website/" \
--wait
Replace acme-web with your Quave ONE app slug and acme-web-staging with the source environment to clone. Set --dir to the source root for a monorepo or omit it to deploy the checkout root. The workflow uses a user token because preview creation copies source environment configuration and secrets. Store it as the QUAVEONE_USER_TOKEN repository secret in GitHub.
Use branches-ignore to keep production branches on your normal deployment workflow. ttl-hours is the maximum lifetime of each preview, up to 168 hours. idle-hours removes a preview earlier when it has no ingress traffic for the full idle window.
If you prefer the published Action inputs over direct CLI commands, set preview: "true". The Action maps app, from, ttl-hours, optional idle-hours, optional commit-sha, optional prevent-destroy, dir, and CLI wait arguments to the single preview deploy command. The preview URL and deployment output appear in workflow logs. For delete-on-pr-close, env must be the exact CLI preview name printed by an earlier deployment; otherwise use the required TTL cleanup.
Override the Startup Command
The deploy action forwards cli-extra-args to quaveone deploy. This lets one
image run as an API in one environment and as a worker in another:
- name: Deploy worker
uses: quaveone/quaveone-deploy-action@main
with:
user-token: ${{ secrets.QUAVEONE_USER_TOKEN }}
env: "acme-worker-production"
image: "ghcr.io/acme/platform:${{ github.sha }}"
cli-extra-args: >-
--command "bun run start:worker"
--working-dir /app
--wait
The override is saved on the environment. It works with either image or
dir, and changing it does not change the image or source-build hash. To return
to the image defaults in a later deployment, use:
cli-extra-args: "--clear-command --wait"
For direct execution, repeatable arguments, and args-only behavior, see Startup Command Overrides.
Deploying from a Mono Repo
If your app lives inside a folder of a mono repo, use the dir parameter to point our GitHub Action at the app's source code, and use paths to trigger the deployment only when that folder changes.
Let's suppose you have a mono repo with two apps: my-app (code in the folder my-app inside the mono repo root) and another-app (code in the folder another-app inside the mono repo root).
To deploy my-app only when you have changes at my-app folder in the main branch, create a yaml file at .github/workflows/quaveone-deploy-my-app.yml with the following content:
name: Deploy my-app
on:
push:
branches: ['main']
paths: ['my-app/**', '.github/workflows/quaveone-deploy-my-app.yml']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Deploy
uses: quaveone/quaveone-deploy-action@main
with:
user-token: ${{ secrets.QUAVEONE_USER_TOKEN }}
env: "customer-my-app"
dir: "my-app/"
You can then create a similar workflow file for another-app, swapping the paths, env and dir values.
Deploying after running tests
It's very common to want to run tests before deploying your app. For example, you might want to run tests before deploying to make sure your app is working as expected.
Also, it's common to need to install some dependencies before running tests. For example, you might want to install Meteor before running tests to use Meteor binary to run the tests.
In the example below you can see how you can do that.
name: Deploy
on:
push:
branches: ['main']
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version: '24.x'
- name: Install Dependencies
run: |
curl https://install.meteor.com | /bin/sh && meteor npm i
- name: Run Check
run: |
meteor npm run quave-check
- name: Run Tests
run: |
meteor npm run test
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Deploy App
uses: quaveone/quaveone-deploy-action@main
with:
user-token: ${{ secrets.QUAVEONE_USER_TOKEN }}
env: "your-env-name"
Deploy using our CLI
If you want to use our CLI directly from a GitHub action instead of using our GitHub Action you can do it like this:
name: CLI Deploy
on:
push:
branches: ['main']
paths: ['my-app/**', '.github/workflows/quaveone-deploy-my-app.yml']
jobs:
deploy:
runs-on: ubuntu-latest
container:
image: quaveone/quaveone-cli:latest
env:
QUAVEONE_USER_TOKEN: ${{ secrets.QUAVEONE_USER_TOKEN }}
steps:
- uses: actions/checkout@v7
- name: Deploy with Quave ONE CLI
env:
QUAVEONE_USER_TOKEN: ${{ secrets.QUAVEONE_USER_TOKEN }}
run: quaveone deploy --env "customer-my-app" --dir "docs"
Both are going to result in the same deploy command being triggered by our CLI. Keep authentication token-based in CI (user-token, env-token, QUAVEONE_USER_TOKEN, or QUAVEONE_ENV_TOKEN); do not rely on local quaveone login state inside GitHub Actions.
Rails migrations before deploy
For Rails apps, run the migration as a Quave ONE JobRun and wait for it before deploying the web app image. The migration command exits non-zero unless the JobRun reaches SUCCEEDED, so GitHub Actions stops before the app deploy when the migration fails. Use the Rails command that exists inside your container, usually bin/rails db:migrate for apps with Rails binstubs or bundle exec rails db:migrate.
See the complete working example in quaveone/rails-migration-job-demo. It builds one Rails image, runs quaveone job run --wait for bin/rails db:migrate, deploys the web app with quaveone deploy --wait, and smoke-tests the migrated app.
name: Rails deploy
on:
push:
branches: ['main']
jobs:
deploy:
runs-on: ubuntu-latest
env:
IMAGE: ghcr.io/acme/rails-app:${{ github.sha }}
QUAVEONE_USER_TOKEN: ${{ secrets.QUAVEONE_USER_TOKEN }}
steps:
- uses: actions/checkout@v7
- name: Install Quave ONE CLI
run: |
mkdir -p "$RUNNER_TEMP/quaveone"
curl -fsSL https://raw.githubusercontent.com/quaveone/cli/main/install.sh | QUAVEONE_INSTALL_DIR="$RUNNER_TEMP/quaveone" bash
echo "$RUNNER_TEMP/quaveone" >> "$GITHUB_PATH"
- name: Build and push image
run: |
docker build -t "$IMAGE" .
docker push "$IMAGE"
- name: Run Rails migration
run: |
quaveone job run \
--env "acme-rails-migration-prod" \
--image "$IMAGE" \
--command "bin/rails db:migrate" \
--wait \
--timeout-seconds 1800 \
--backoff-limit 0 \
--logs-on-failure
- name: Deploy Rails web app
run: |
quaveone deploy \
--env "acme-rails-web-prod" \
--image "$IMAGE" \
--wait
Deploying to a Full Private Region
If you use Quave ONE Connect Full Private, you need to specify the custom API URL using the api-cli-uri parameter.
name: Private Region Deploy
on:
push:
branches: [ 'main' ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Deploy to Private Region
uses: quaveone/quaveone-deploy-action@main
with:
user-token: ${{ secrets.QUAVEONE_USER_TOKEN }}
env: "my-private-env"
api-cli-uri: "https://your-private-api.example.com"
The api-cli-uri should point to your private Quave ONE API endpoint. Contact your infrastructure team to get the
correct URL for your private region.