
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.
Status: Beta
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.0 cut.
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.2 matches 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.
Quick start
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 apply
A 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.
What you can manage
| 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.
Configuration
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.
Examples
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.
Common workflows
Renaming resources without recreating
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
}
Importing existing infrastructure
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-…
Custom domain verification
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.
Contributing
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 docs
The 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.
License
MPL-2.0