Manage DevHelm monitoring, alerting, status pages, and incident management as code.
The provider is the recommended way to manage DevHelm at scale: it gives you
a stable Terraform identity for every resource (so renames are non-destructive
via the built-in moved {} block), composes naturally with for_each and
modules, and integrates cleanly with DNS providers, secret stores, and other
parts of your platform stack.
The DevHelm Terraform provider is currently in 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. We're
running it through a short soak window to harden one defense-in-depth
edge case (post-POST failure rollback in the API client) before
promoting to GA.
What this means in practice:
- ✅ Safe for production use — the schema and on-disk state format
will not change in backward-incompatible ways before the
1.0.0cut. All breaking changes (if any) will go through a deprecation cycle and ship in a clearly-versioned beta first. - ✅ Fully supported — file issues at devhelmhq/terraform-provider-devhelm; beta does not mean unsupported.
⚠️ Pin the exact pre-release version. Terraform's~>operator does not select pre-release versions, so a constraint like~> 0.2matches zero published versions today. Use the exact pin shown in the snippet below.⚠️ Track the CHANGELOG for each beta bump until GA. We don't expect breaking changes between betas, but we do reserve the right to ship them with a clearly-flagged release note if a real production failure forces our hand.
After 1.0.0, switch your pin to ~> 1.0 and rely on
semver.
terraform {
required_version = ">= 1.5.0"
required_providers {
devhelm = {
source = "devhelmhq/devhelm"
version = "0.2.0-beta.4" # Beta — pin the exact version, see "Status: Beta" above
}
}
}
provider "devhelm" {}
resource "devhelm_alert_channel" "ops" {
name = "Ops Email"
channel_type = "email"
recipients = ["ops@example.com"]
}
resource "devhelm_monitor" "api" {
name = "Public API"
type = "HTTP"
frequency_seconds = 60
config = jsonencode({ url = "https://api.example.com/health", method = "GET" })
alert_channel_ids = [devhelm_alert_channel.ops.id]
assertions {
type = "status_code"
config = jsonencode({ expected = 200 })
}
}export DEVHELM_API_TOKEN=… # create at https://app.devhelm.io/settings/tokens
terraform init
terraform plan
terraform applyA full quickstart, plus end-to-end examples for status pages, custom domains, notification policies, and resource groups lives at the Getting Started with Terraform guide.
| Category | Resources / Data sources |
|---|---|
| Monitoring | devhelm_monitor, devhelm_environment, devhelm_secret, devhelm_tag |
| Alerting | devhelm_alert_channel, devhelm_notification_policy, devhelm_webhook |
| Fleet management | devhelm_resource_group, devhelm_resource_group_membership |
| Third-party deps | devhelm_dependency |
| Status pages | devhelm_status_page, devhelm_status_page_component_group, devhelm_status_page_component |
| Custom domains | devhelm_status_page_custom_domain, devhelm_status_page_custom_domain_verification |
| Look-up data sources | devhelm_monitor, devhelm_alert_channel, devhelm_environment, devhelm_resource_group, devhelm_status_page, devhelm_tag |
Per-resource documentation, schemas, and copy-paste examples are published on the Terraform Registry.
All four provider attributes have environment-variable equivalents. The recommended 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 without modification.
| Attribute | Env var | Default | Required |
|---|---|---|---|
token |
DEVHELM_API_TOKEN |
— | yes |
base_url |
DEVHELM_API_URL |
https://api.devhelm.io |
no |
org_id |
DEVHELM_ORG_ID |
1 |
no |
workspace_id |
DEVHELM_WORKSPACE_ID |
1 |
no |
Create an API token at https://app.devhelm.io/settings/tokens. The token should be scoped to the workspace you intend to manage from Terraform.
The examples/ directory holds runnable, copy-paste-ready
configurations for every resource and data source the provider exposes:
examples/
├── provider/ # provider {} block + env-var docs
├── resources/
│ ├── devhelm_monitor/ # HTTP, heartbeat, authenticated
│ ├── devhelm_alert_channel/ # all 7 channel types
│ ├── devhelm_notification_policy/
│ ├── devhelm_status_page/
│ ├── devhelm_status_page_custom_domain/ # end-to-end Cloudflare wiring
│ └── …
└── data-sources/
└── …
Each <resource>/resource.tf is what gets embedded into the Registry
documentation page for that resource via tfplugindocs.
The status-page family (devhelm_status_page, devhelm_status_page_component_group,
devhelm_status_page_component) all assign stable UUIDs server-side. Renaming
the Terraform address with a moved {} block preserves the underlying UUID,
incident history, and subscriber list — no destructive delete/recreate.
moved {
from = devhelm_status_page_component.api
to = devhelm_status_page_component.public_api
}
resource "devhelm_status_page_component" "public_api" {
status_page_id = devhelm_status_page.public.id
name = "Public API"
type = "MONITOR"
monitor_id = devhelm_monitor.api.id
}Every resource implements ImportState. Most resources accept either a UUID
or a human-friendly identifier (name / slug / key); see the import command
example in each resource's docs page.
# Single-segment imports
terraform import devhelm_monitor.api "Public API"
terraform import devhelm_status_page.public acme
# Compound imports (parent/child resources)
terraform import devhelm_status_page_component.api \
7f819203-…/9182b3c4-…The devhelm_status_page_custom_domain resource exposes the DNS records you
need to create at your DNS provider, and the companion
devhelm_status_page_custom_domain_verification resource blocks
terraform apply until the API confirms verification — modeled on the
well-known aws_acm_certificate_validation pattern. See the
full example.
Local development:
git clone https://github.com/devhelmhq/terraform-provider-devhelm
cd terraform-provider-devhelm
# Build + install into ~/.terraform.d/plugins so dev_overrides resolves it
make install
# Run the unit + framework acceptance tests (the latter requires Terraform on PATH)
make test
TF_ACC=1 make testacc
# Regenerate docs/ after editing schema descriptions or examples/
make docsThe Go acceptance tests use an in-process mock API server so they run
in <1s per scenario — see internal/provider/framework_test.go.
End-to-end surface tests that drive a real terraform apply against the
DevHelm API live in the monorepo at
tests/surfaces/terraform_provider_devhelm/
and are run on every PR via the surface_release integration test workflow.