Using the CLI in CI/CD Pipelines
The DeployHQ CLI works seamlessly in CI/CD pipelines. Authentication uses environment variables, so no interactive login is needed.
Setup
1. Set Secrets
Add these secrets to your CI provider:
| Secret | Description |
|---|---|
DEPLOYHQ_ACCOUNT |
Your account subdomain (e.g. mycompany) |
DEPLOYHQ_EMAIL |
API user email |
DEPLOYHQ_API_KEY |
API key (found in Settings > Security) |
2. Install the CLI
Use the install script in your pipeline:
curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh
3. Deploy
dhq deploy --server production --revision $COMMIT_SHA --wait --json
The --wait flag blocks until the deployment finishes, and --json provides machine-readable output for parsing results.
GitHub Actions Examples
Basic Deployment
Deploy to production on push to main:
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
env:
DEPLOYHQ_ACCOUNT: ${{ secrets.DEPLOYHQ_ACCOUNT }}
DEPLOYHQ_EMAIL: ${{ secrets.DEPLOYHQ_EMAIL }}
DEPLOYHQ_API_KEY: ${{ secrets.DEPLOYHQ_API_KEY }}
DEPLOYHQ_PROJECT: my-app
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Install DeployHQ CLI
run: curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh
- name: Deploy to production
run: dhq deploy --server production --revision ${{ github.sha }} --wait --json
- name: Show deployment logs (on failure)
if: failure()
run: |
DEP_ID=$(dhq deployments list --json | jq -r '.data.records[0].identifier')
dhq deployments logs "$DEP_ID"
Multi-Environment Deployment
Deploy to staging on push, production on release, with auto-rollback:
# .github/workflows/deploy-multi-env.yml
name: Deploy (multi-environment)
on:
push:
branches: [main]
release:
types: [published]
env:
DEPLOYHQ_ACCOUNT: ${{ secrets.DEPLOYHQ_ACCOUNT }}
DEPLOYHQ_EMAIL: ${{ secrets.DEPLOYHQ_EMAIL }}
DEPLOYHQ_API_KEY: ${{ secrets.DEPLOYHQ_API_KEY }}
DEPLOYHQ_PROJECT: my-app
jobs:
deploy-staging:
if: github.event_name == 'push'
runs-on: ubuntu-latest
environment: staging
steps:
- name: Install DeployHQ CLI
run: curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh
- name: Deploy to staging
run: dhq deploy --server staging --revision ${{ github.sha }} --wait --json
deploy-production:
if: github.event_name == 'release'
runs-on: ubuntu-latest
environment: production
steps:
- name: Install DeployHQ CLI
run: curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh
- name: Deploy to production
run: dhq deploy --server production --revision ${{ github.sha }} --wait --json
- name: Rollback on failure
if: failure()
run: |
PREV=$(dhq deployments list --json | jq -r '.data.records[1].identifier')
dhq rollback "$PREV" --json
Deploy on PR Merge with Status Comment
Deploy when a PR is merged, then post a deployment summary as a PR comment:
# .github/workflows/deploy-on-pr-merge.yml
name: Deploy on PR merge
on:
pull_request:
types: [closed]
branches: [main]
env:
DEPLOYHQ_ACCOUNT: ${{ secrets.DEPLOYHQ_ACCOUNT }}
DEPLOYHQ_EMAIL: ${{ secrets.DEPLOYHQ_EMAIL }}
DEPLOYHQ_API_KEY: ${{ secrets.DEPLOYHQ_API_KEY }}
DEPLOYHQ_PROJECT: my-app
jobs:
deploy:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Install DeployHQ CLI
run: curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh
- name: Deploy and wait
id: deploy
run: |
RESULT=$(dhq deploy \
--server production \
--revision ${{ github.event.pull_request.merge_commit_sha }} \
--wait --json)
DEP_ID=$(echo "$RESULT" | jq -r '.data.identifier')
STATUS=$(echo "$RESULT" | jq -r '.data.status')
DURATION=$(echo "$RESULT" | jq -r '.data.timestamps.duration // "?"')
SERVERS=$(echo "$RESULT" | jq -r '.data.servers | length')
echo "deployment_id=$DEP_ID" >> "$GITHUB_OUTPUT"
echo "status=$STATUS" >> "$GITHUB_OUTPUT"
echo "duration=$DURATION" >> "$GITHUB_OUTPUT"
echo "servers=$SERVERS" >> "$GITHUB_OUTPUT"
- name: Comment on PR
if: always()
uses: actions/github-script@v7
with:
script: |
const status = '${{ steps.deploy.outputs.status }}' || 'unknown';
const depId = '${{ steps.deploy.outputs.deployment_id }}';
const duration = '${{ steps.deploy.outputs.duration }}';
const servers = '${{ steps.deploy.outputs.servers }}';
const icon = status === 'completed' ? ':white_check_mark:' : ':x:';
const body = `${icon} **Deployment ${status}**
| Field | Value |
|-------|-------|
| ID | \`${depId}\` |
| Duration | ${duration}s |
| Servers | ${servers} |
| Revision | \`${{ github.event.pull_request.merge_commit_sha }}\` |`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body
});
GitLab CI
# .gitlab-ci.yml
deploy:
stage: deploy
image: ubuntu:latest
variables:
DEPLOYHQ_ACCOUNT: $DEPLOYHQ_ACCOUNT
DEPLOYHQ_EMAIL: $DEPLOYHQ_EMAIL
DEPLOYHQ_API_KEY: $DEPLOYHQ_API_KEY
DEPLOYHQ_PROJECT: my-app
script:
- curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh
- dhq deploy --server production --revision $CI_COMMIT_SHA --wait --json
only:
- main
Bitbucket Pipelines
# bitbucket-pipelines.yml
pipelines:
branches:
main:
- step:
name: Deploy
script:
- curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh
- dhq deploy --server production --revision $BITBUCKET_COMMIT --wait --json
Set DEPLOYHQ_ACCOUNT, DEPLOYHQ_EMAIL, and DEPLOYHQ_API_KEY as repository variables in Bitbucket.
Tips for CI/CD
Parsing JSON Output
Use jq to extract specific fields from JSON output:
# Get deployment status
dhq deployments show abc123 -p my-app --json | jq -r '.data.status'
# Get the latest deployment ID
dhq deployments list -p my-app --json | jq -r '.data.records[0].identifier'
Non-Zero Exit Codes
The CLI returns non-zero exit codes on failure, so your CI pipeline will automatically fail if a deployment fails when using --wait.
DEPLOYHQ_PROJECT Environment Variable
Set DEPLOYHQ_PROJECT to avoid passing -p on every command:
export DEPLOYHQ_PROJECT=my-app
dhq deploy --server production --wait
Security
- Always store credentials as CI secrets, never in pipeline configuration files
- Use the minimum required permissions for the API key
- Consider using a dedicated service account for CI/CD deployments