> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devhelm.io/llms.txt
> Use this file to discover all available pages before exploring further.

# CI/CD Pipeline

> Deploy DevHelm monitoring configuration automatically from GitHub Actions

By the end of this guide, you'll have a GitHub Actions workflow that validates, plans, and deploys your monitoring config on every push to `main`, with plan previews on pull requests.

<Accordion title="Prerequisites">
  * A `devhelm.yml` file in your repository — see [Monitoring as Code tutorial](/guides/monitoring-as-code)
  * A DevHelm API token stored as a GitHub secret (`DEVHELM_API_TOKEN`)
</Accordion>

## Deploy workflow

Create `.github/workflows/devhelm-deploy.yml`:

```yaml theme={null}
name: Deploy Monitoring Config
on:
  push:
    branches: [main]
    paths: ['devhelm.yml']

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: devhelmhq/setup-devhelm@v1
        with:
          api-token: ${{ secrets.DEVHELM_API_TOKEN }}

      - name: Validate
        run: devhelm validate devhelm.yml

      - name: Deploy
        run: devhelm deploy -f devhelm.yml --yes
```

The `--yes` flag skips interactive confirmation — required for non-interactive CI environments.

## PR preview workflow

Show what would change before merging. Create `.github/workflows/devhelm-plan.yml`:

```yaml theme={null}
name: Monitor Config Preview
on:
  pull_request:
    paths: ['devhelm.yml']

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: devhelmhq/setup-devhelm@v1
        with:
          api-token: ${{ secrets.DEVHELM_API_TOKEN }}

      - name: Validate
        run: devhelm validate devhelm.yml

      - name: Plan
        run: devhelm plan -f devhelm.yml
```

The plan output shows resources to create, update, and delete — review it in the Actions log before merging.

## Gate merges on config validity

Use `--dry-run --detailed-exitcode` to block PRs that would cause deployment errors:

```yaml theme={null}
      - name: Dry run
        run: devhelm deploy -f devhelm.yml --dry-run --detailed-exitcode
```

Exit codes:

* `0` — no changes needed
* `10` — changes pending (valid config, would apply changes)
* `4` — validation error (invalid config)
* `11` — API error (auth failure, held deploy lock, server error)

Use this as a required status check to prevent merging broken configs.

## Add a maintenance window for deploys

Suppress alerts during the deployment window:

```yaml theme={null}
      - name: Create maintenance window
        run: |
          devhelm maintenance-windows create \
            --start "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
            --end   "$(date -u -d '+15 minutes' +%Y-%m-%dT%H:%M:%SZ)" \
            --reason "CI deployment ${{ github.sha }}"

      - name: Deploy application
        run: ./scripts/deploy.sh

      - name: Deploy monitoring config
        run: devhelm deploy -f devhelm.yml --yes
```

## Multiple environments

For staging and production environments, see [Multi-environment config](/guides/multi-environment-config). Use separate workflow files or environment-specific API tokens:

```yaml theme={null}
jobs:
  deploy-staging:
    environment: staging
    steps:
      - uses: devhelmhq/setup-devhelm@v1
        with:
          api-token: ${{ secrets.DEVHELM_API_TOKEN_STAGING }}
      - run: devhelm deploy -f devhelm.staging.yml --yes

  deploy-production:
    needs: deploy-staging
    environment: production
    steps:
      - uses: devhelmhq/setup-devhelm@v1
        with:
          api-token: ${{ secrets.DEVHELM_API_TOKEN_PRODUCTION }}
      - run: devhelm deploy -f devhelm.production.yml --yes
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Deploy fails with 'lock held'">
    Another deploy is running. Deploy locks prevent concurrent deploys. Wait for the other deploy to finish, or force unlock if it's stuck:

    ```bash theme={null}
    devhelm deploy force-unlock --yes
    ```
  </Accordion>

  <Accordion title="Validation passes but deploy fails">
    Validation checks syntax offline. The API may reject the config if a referenced secret doesn't exist or a resource name conflicts. Check the error message for details.
  </Accordion>

  <Accordion title="setup-devhelm action fails">
    Verify that `DEVHELM_API_TOKEN` is set as a repository secret (not an environment variable). The action uses it to authenticate all CLI commands.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Multi-environment config" icon="code-branch" href="/guides/multi-environment-config">
    Manage staging and production separately.
  </Card>

  <Card title="GitHub Actions setup" icon="github" href="/integrations/github-actions">
    Full setup-devhelm action reference.
  </Card>

  <Card title="Monitoring as Code tutorial" icon="file-code" href="/guides/monitoring-as-code">
    Complete YAML format and workflow guide.
  </Card>
</CardGroup>
