Rootly Terraform Provider: On-Call and Incidents as Code

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.

Your privacy choices

Rootly uses cookies from advertising partners to measure our ads and to show ads for Rootly on other sites. Some US state laws call that selling or sharing personal information. You can opt out of it for this browser here.

Analytics we use to improve this site stay on. Read Rootly's Privacy policy for more information.