Rootly Terraform Provider: On-Call and Incidents as Code
Published
Rootly Terraform Provider: On-Call and Incidents as Code
On this page
Rootly has an official Terraform provider, rootlyhq/rootly on the Terraform Registry. It manages Rootly configuration as code: on-call schedules and rotations, escalation policies, alert routes, teams, services, severities, workflows, forms, status pages, and retrospective processes. The Rootly Terraform docs list more than 200 resources and 59 data sources. The provider is included on every Rootly plan.
Managing on-call as code turns a rotation change into a reviewable diff. A new service gets its schedule, escalation policy, and alert route from the same module every other service uses, and terraform plan shows what will change before anyone’s pager does.
What the Rootly Terraform provider manages
| Area | Resources |
|---|---|
| On-call | rootly_schedule, rootly_schedule_rotation, rootly_schedule_rotation_user, rootly_schedule_rotation_active_day, rootly_override_shift, rootly_on_call_shadow, rootly_on_call_role |
| Escalation | rootly_escalation_policy, rootly_escalation_path, rootly_escalation_level |
| Alerts | rootly_alerts_source, rootly_alert_route, rootly_alert_routing_rule, rootly_alert_group, rootly_alert_urgency, rootly_alert_field, rootly_heartbeat |
| Teams and catalog | rootly_team, rootly_service, rootly_functionality, rootly_catalog, rootly_catalog_entity, rootly_catalog_property |
| Incidents | rootly_severity, rootly_incident_type, rootly_incident_role, rootly_environment, rootly_cause, rootly_form_field, rootly_form_set |
| Workflows | rootly_workflow_incident, rootly_workflow_alert, rootly_workflow_pulse, rootly_workflow_simple, and one resource per workflow task type, such as rootly_workflow_task_send_slack_message |
| Status pages and retrospectives | rootly_status_page, rootly_status_page_template, rootly_retrospective_process, rootly_post_mortem_template |
| Access and communications | rootly_role, rootly_communications_template, rootly_webhooks_endpoint, rootly_secret |
Data sources such as rootly_user, rootly_team, rootly_service, rootly_schedule, and rootly_escalation_policy let a configuration reference objects that are managed elsewhere. The full list is in the registry documentation.
Install and authenticate
Declare the provider and run terraform init. The provider reads a Rootly API token from the ROOTLY_API_TOKEN environment variable, so the token stays out of your configuration.
terraform {
required_providers {
rootly = {
source = "rootlyhq/rootly"
version = "~> 5.10"
}
}
}
provider "rootly" {
# Reads ROOTLY_API_TOKEN from the environment.
}
Example: an on-call schedule with a daily rotation
A schedule holds one or more rotations, and each rotation lists its responders in order. This rotation hands off every day at 09:00 New York time.
data "rootly_user" "alice" {
email = "alice@example.com"
}
data "rootly_user" "bob" {
email = "bob@example.com"
}
resource "rootly_team" "payments" {
name = "Payments"
user_ids = [data.rootly_user.alice.id, data.rootly_user.bob.id]
}
resource "rootly_schedule" "payments_primary" {
name = "Payments primary"
owner_group_ids = [rootly_team.payments.id]
all_time_coverage = true
}
resource "rootly_schedule_rotation" "daily" {
schedule_id = rootly_schedule.payments_primary.id
name = "Daily handoff"
schedule_rotationable_type = "ScheduleDailyRotation"
schedule_rotationable_attributes = {
handoff_time = "09:00"
}
active_all_week = true
time_zone = "America/New_York"
position = 1
}
resource "rootly_schedule_rotation_user" "alice" {
schedule_rotation_id = rootly_schedule_rotation.daily.id
user_id = data.rootly_user.alice.id
position = 1
}
resource "rootly_schedule_rotation_user" "bob" {
schedule_rotation_id = rootly_schedule_rotation.daily.id
user_id = data.rootly_user.bob.id
position = 2
}
Example: an escalation policy that pages the schedule
An escalation policy has paths, and each path has numbered levels. The first level pages whoever is on call on the schedule above. If nobody acknowledges within 10 minutes, the second level pages every member of the Payments team.
resource "rootly_escalation_policy" "payments" {
name = "Payments escalation"
group_ids = [rootly_team.payments.id]
}
resource "rootly_escalation_path" "default" {
name = "Default"
default = true
escalation_policy_id = rootly_escalation_policy.payments.id
}
resource "rootly_escalation_level" "on_call" {
escalation_policy_id = rootly_escalation_policy.payments.id
escalation_policy_path_id = rootly_escalation_path.default.id
position = 1
delay = 10
notification_target_params {
type = "schedule"
id = rootly_schedule.payments_primary.id
}
}
resource "rootly_escalation_level" "team" {
escalation_policy_id = rootly_escalation_policy.payments.id
escalation_policy_path_id = rootly_escalation_path.default.id
position = 2
notification_target_params {
type = "team"
id = rootly_team.payments.id
team_members = "all"
}
}
Example: a service and an incident workflow
The service points at the escalation policy, so alerts for it page the Payments rotation. The workflow posts a message to the incident’s Slack channel when an incident starts.
resource "rootly_service" "payments_api" {
name = "payments-api"
escalation_policy_id = rootly_escalation_policy.payments.id
}
resource "rootly_workflow_incident" "kickoff" {
name = "Post the kickoff checklist"
enabled = true
trigger_params {
triggers = ["incident_created"]
incident_condition_status = "IS"
incident_statuses = ["started"]
}
}
resource "rootly_workflow_task_send_slack_message" "kickoff" {
workflow_id = rootly_workflow_incident.kickoff.id
task_params {
text = "Incident declared. Assign an incident commander and post the first update within 15 minutes."
channels {
id = "{{ incident.slack_channel_id }}"
name = "{{ incident.slack_channel_id }}"
}
}
}
The provider repository has fuller examples for each resource, including round-robin paging strategies and alert routes with conditions, in examples/resources.
Import configuration you already have
Configuration created in the Rootly UI can be brought under Terraform without recreating it:
terraform import rootly_schedule.payments_primary <schedule-id>
terraform import rootly_escalation_policy.payments <escalation-policy-id>
terraform import rootly_service.payments_api <service-id>
Resource IDs are in the Rootly API and in the dashboard URL when you open a resource. Teams that prefer a general-purpose language can manage the same configuration with Pulumi.
Frequently asked questions
Everything you need to know about managing Rootly with Terraform.
Does Rootly have a Terraform provider?
Yes. The official provider is rootlyhq/rootly on the Terraform Registry. It manages Rootly configuration as code, including on-call schedules, escalation policies, alert routes, teams, services, severities, workflows, and status pages, with more than 200 resources and 59 data sources.
Can I manage on-call schedules and escalation policies with Terraform?
Yes. rootly_schedule, rootly_schedule_rotation and rootly_schedule_rotation_user define schedules and who is on them, and rootly_escalation_policy, rootly_escalation_path and rootly_escalation_level define who gets paged and when. rootly_alert_route decides which escalation policy an incoming alert reaches.
Can I bring existing Rootly configuration under Terraform?
Yes. Use terraform import with the resource ID, which is available from the Rootly API or the dashboard URL. The resource is adopted into state without being recreated.
Which Rootly plans include the Terraform provider?
The Terraform provider is included on every Rootly plan, as listed on the Rootly pricing page.
Is there an alternative to Terraform for managing Rootly as code?
Rootly also documents a Pulumi integration, and the Rootly REST API, CLI and SDKs cover the same configuration for teams that build their own tooling.