Skip to main content
Structure your YAML configs and CI workflows to handle multiple environments with shared base definitions and per-environment overrides.

File structure

Separate files per environment

The simplest approach — one file per environment:
devhelm.staging.yml
devhelm.production.yml
Each file is self-contained. Deploy the right file based on the branch or CI environment.

Base + override files

Share common definitions in a base file and override per environment:
config/
  base.yml          # shared monitors, channels, policies
  staging.yml       # staging-specific overrides
  production.yml    # production-specific overrides
Deploy with multiple -f flags:
devhelm deploy -f config/base.yml -f config/staging.yml --yes
Resources are merged by name — the last file wins for duplicate names.

Using environment variables

Share a single file and vary behavior with environment variables:
monitors:
  - name: API Health
    type: HTTP
    config:
      url: ${API_URL}
    frequency: ${CHECK_FREQUENCY:-60}
Set different values in each CI environment:
# Staging
API_URL=https://staging-api.example.com CHECK_FREQUENCY=300 devhelm deploy -f devhelm.yml --yes

# Production
API_URL=https://api.example.com CHECK_FREQUENCY=60 devhelm deploy -f devhelm.yml --yes

GitHub Actions

Using environments

jobs:
  deploy:
    strategy:
      matrix:
        env: [staging, production]
    environment: ${{ matrix.env }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: devhelmhq/setup-devhelm@v1
        with:
          api-token: ${{ secrets.DEVHELM_API_TOKEN }}
      - run: devhelm deploy -f devhelm.${{ matrix.env }}.yml --yes

Sequential with approval

jobs:
  deploy-staging:
    environment: staging
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: devhelmhq/setup-devhelm@v1
        with:
          api-token: ${{ secrets.DEVHELM_API_TOKEN }}
      - run: devhelm deploy -f devhelm.staging.yml --yes

  deploy-production:
    needs: deploy-staging
    environment: production
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: devhelmhq/setup-devhelm@v1
        with:
          api-token: ${{ secrets.DEVHELM_API_TOKEN }}
      - run: devhelm deploy -f devhelm.production.yml --yes
Configure the production environment in GitHub Settings to require manual approval.

GitLab CI

.deploy-monitoring:
  image: node:20
  script:
    - npm install -g devhelm
    - devhelm validate devhelm.$CI_ENVIRONMENT_NAME.yml
    - devhelm deploy -f devhelm.$CI_ENVIRONMENT_NAME.yml --yes

deploy-staging:
  extends: .deploy-monitoring
  stage: deploy
  environment: staging
  only: [main]

deploy-production:
  extends: .deploy-monitoring
  stage: deploy
  environment: production
  when: manual
  only: [main]

Terraform

Use Terraform workspaces or separate state files:
terraform workspace select staging
terraform apply -var-file=staging.tfvars

terraform workspace select production
terraform apply -var-file=production.tfvars
Or use separate directories:
terraform/
  staging/
    main.tf
    terraform.tfvars
  production/
    main.tf
    terraform.tfvars

Best practices

  • Separate API tokens per environment for isolation
  • Deploy staging first, then promote to production
  • Use GitHub Environments or equivalent for approval gates on production
  • Pin CLI versions for reproducible builds across environments
  • Keep environment differences minimal — vary URLs and frequencies, not monitor structure

Next steps

GitHub Actions

Full setup-devhelm action reference.

Environments CLI

Manage environments from the command line.