Skip to main content

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.

The DevHelm Terraform provider lets you manage your monitoring stack — monitors, alert channels, status pages, secrets, and more — declaratively alongside your cloud infrastructure. The provider is published on the Terraform Registry as devhelmhq/devhelm.
Status: Beta. The schema is stable, the resource set is feature-complete against the DevHelm v1 API, and the provider has been validated end-to-end against production. While the other DevHelm surfaces (CLI, SDKs, MCP server) are now at 1.0.0, the Terraform provider is intentionally held at 0.2.0-beta.x for a short soak window to harden a defense-in-depth rollback path. Safe for production use; pin the exact version below.

Install

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    devhelm = {
      source  = "devhelmhq/devhelm"
      version = "0.2.0-beta.4"
    }
  }
}

provider "devhelm" {}
Pre-release pin required. The provider currently ships only as pre-release versions, and Terraform’s ~> operator never selects pre-releases. Pin the exact version above (0.2.0-beta.4 is the latest published tag); bump it explicitly when the next version ships, or wait for the GA 1.0.0 cut to switch to a range like ~> 1.0. Latest version is on the Registry overview page.
All four provider attributes have environment-variable equivalents and are optional. The most common pattern is to leave the provider block empty and supply credentials through the environment so the same config works locally, in CI, and in Terraform Cloud.
AttributeEnv varDefaultDescription
tokenDEVHELM_API_TOKENRequired. Create at app.devhelm.io/settings/tokens. Sensitive.
base_urlDEVHELM_API_URLhttps://api.devhelm.ioAPI endpoint
org_idDEVHELM_ORG_ID1Organization ID (multi-org tokens only)
workspace_idDEVHELM_WORKSPACE_ID1Workspace ID (multi-workspace tokens only)

Available resources

ResourcePurpose
devhelm_monitorHTTP, DNS, TCP, ICMP, Heartbeat, MCP Server monitors
devhelm_alert_channelSlack, Email, PagerDuty, OpsGenie, Discord, Teams, Webhook
devhelm_notification_policyRouting rules from monitors → channels
devhelm_webhookOutbound webhook subscriptions for platform events
devhelm_secretVault secrets referenced by monitor auth and config
devhelm_environmentPer-environment variable scopes (production, staging, …)
devhelm_tagTags for filtering and grouping
devhelm_resource_groupService / team groupings
devhelm_resource_group_membershipAdd a user to a resource group
devhelm_dependencyTrack third-party SaaS components (GitHub, Stripe, …)
devhelm_status_pagePublic or private status pages
devhelm_status_page_componentComponents shown on a status page
devhelm_status_page_component_groupGroup components into sections
devhelm_status_page_custom_domainCustom domain attached to a status page
devhelm_status_page_custom_domain_verificationDNS / TLS verification record

Available data sources

devhelm_monitor, devhelm_alert_channel, devhelm_environment, devhelm_resource_group, devhelm_status_page, devhelm_tag. See Data sources.

Quick example

resource "devhelm_tag" "production" {
  name  = "production"
  color = "#10b981"
}

resource "devhelm_alert_channel" "ops_slack" {
  name         = "Engineering Slack"
  channel_type = "slack"
  webhook_url  = var.slack_webhook_url
  mention_text = "@channel"
}

resource "devhelm_monitor" "api_health" {
  name              = "API Health"
  type              = "HTTP"
  frequency_seconds = 60
  regions           = ["us-east", "eu-west"]

  config = jsonencode({
    url       = "https://api.example.com/health"
    method    = "GET"
    verifyTls = true
  })

  assertions {
    type   = "status_code"
    # `expected` is a STRING — quote even plain numeric codes. `200`
    # (number) plans cleanly but apply fails with "Provider produced
    # inconsistent result" because the API normalizes to "200" (string).
    config = jsonencode({ expected = "200", operator = "equals" })
  }

  assertions {
    type     = "response_time"
    config   = jsonencode({ thresholdMs = 2000 })
    severity = "warn"
  }

  tag_ids           = [devhelm_tag.production.id]
  alert_channel_ids = [devhelm_alert_channel.ops_slack.id]
}
config and assertions[].config are JSON strings (not HCL blocks). Use jsonencode({...}) and camelCase field names — they map directly to the API wire format (thresholdMs, verifyTls, expectedInterval, …). The provider validates the payload against the generated schema at plan time, so unknown fields fail fast.

Import existing resources

Every resource supports terraform import. Most are imported by their human-readable name or slug:
terraform import devhelm_monitor.api_health "API Health"
terraform import devhelm_alert_channel.ops_slack "Engineering Slack"
terraform import devhelm_tag.production "production"
See Importing resources for the full ID table.

When to use Terraform vs YAML

Use caseRecommended tool
Monitors managed alongside cloud infra (AWS, GCP, etc.)Terraform provider
Standalone monitoring config, fast iterationdevhelm.yml + CLI
CI/CD with GitHub Actiondevhelm.yml + setup-devhelm action
Mixed infra — some Terraform, some standaloneUse both (avoid managing the same resource in both)
Don’t manage the same resource with both Terraform and devhelm.yml. Pick one source of truth per resource to avoid drift and conflicts.

Next steps

Terraform monitors

Full devhelm_monitor resource reference.

Alert channels

Channel-type-specific arguments.

Importing resources

Import existing resources into Terraform state.

Terraform in CI/CD

Automate Terraform plans and applies in CI.