Public preview Grafana Cloud
Last reviewed: October 13, 2026

Use Terraform

Note

Grafana Workflows is currently in public preview. Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available.

You can manage Grafana Workflows with the Grafana Terraform provider. The provider doesn’t have a dedicated workflow resource. Instead, you use its general-purpose grafana_apps_generic_resource, which accepts a workflow definition as its manifest.

Terraform creates, updates, and deletes workflows. It doesn’t run them. To run a workflow or read its results, refer to Use gcx or Use the API.

Note

The Grafana Terraform provider marks grafana_apps_generic_resource as experimental, and the way it compares changes might change. Pin the provider version, and review each plan before you apply it.

Before you begin

Before you start, make sure you have:

  • Terraform installed.
  • A Grafana Cloud stack with the Workflows app installed.
  • A service account token with the Editor basic role and edit access to the folders Terraform writes to. For details, refer to Service accounts and Manage access.

Configure the provider

Add the Grafana provider to your Terraform files, and set url to your stack’s URL. The provider finds your stack’s namespace for you.

hcl
terraform {
  required_providers {
    grafana = {
      source  = "grafana/grafana"
      version = ">= 4.46.0"
    }
  }
}

provider "grafana" {
  url = "https://<STACK_SLUG>.grafana.net/"
}

Keep the token out of your Terraform files. Instead, set it in the GRAFANA_AUTH environment variable before you run Terraform:

Bash
export GRAFANA_AUTH="<SERVICE_ACCOUNT_TOKEN>"

Create a workflow from a YAML file

Keep each workflow in its own YAML file, and load the file into Terraform with the yamldecode function. To start from a workflow you built in the editor, copy its definition from More > View JSON.

To create a workflow with Terraform, follow these steps:

  1. Save the following definition as workflows/incident-kickoff.yaml, and replace FOLDER_UID with your folder UID.

    The workflow runs when someone creates an incident. Its one step builds a summary.

    YAML
    apiVersion: workflows.ext.grafana.app/v1alpha1
    kind: Definition
    metadata:
      name: incident-kickoff
      annotations:
        grafana.app/folder: <FOLDER_UID>
    spec:
      name: Incident kickoff
      enabled: true
      startWhen:
        matchingRules:
          - eventNameRegex: grafana_irm_app\.incident\.updated
            filter: "inputs.data.eventKind == 'incident_created'"
        schedules: []
      steps:
        - id: summary
          name: Build summary
          type: transform
          inputs:
            template: "New incident: ${resources.incident.event.title}"

    If you copied the file from the editor or the API, remove the fields that Grafana adds. These are resourceVersion, uid, generation, and managedFields.

  2. Add a resource that loads the file:

    hcl
    resource "grafana_apps_generic_resource" "incident_kickoff" {
      manifest = yamldecode(file("${path.module}/workflows/incident-kickoff.yaml"))
    }
  3. Preview the change:

    Bash
    terraform plan

    The plan shows one resource to add.

  4. Create the workflow:

    Bash
    terraform apply

    If the file has a problem, the apply stops and names it, for example, step "summary" is missing required field "template" for type "transform".

  5. Confirm the workflow exists. Open the Workflows app, go to Manage workflows, and find Incident kickoff.

Manage a folder of workflow files

To manage every YAML file in a folder with one resource block, use for_each with the fileset function:

hcl
resource "grafana_apps_generic_resource" "workflow" {
  for_each = fileset("${path.module}/workflows", "*.yaml")

  manifest = yamldecode(file("${path.module}/workflows/${each.value}"))
}

When you add a YAML file, the next apply creates a workflow. When you remove a file, the next apply deletes its workflow.

Create the Grafana folder with Terraform

Every workflow needs the grafana.app/folder annotation. If Terraform also manages the Grafana folder, use the folder’s UID from Terraform instead of typing it.

The following example creates a folder. It then uses the merge function to add the folder’s UID to your YAML file’s contents. With this pattern, the YAML file can leave out annotations.

hcl
resource "grafana_folder" "automation" {
  title = "Incident automation"
}

locals {
  kickoff = yamldecode(file("${path.module}/workflows/incident-kickoff.yaml"))
}

resource "grafana_apps_generic_resource" "incident_kickoff" {
  manifest = merge(local.kickoff, {
    metadata = merge(local.kickoff.metadata, {
      annotations = {
        "grafana.app/folder" = grafana_folder.automation.uid
      }
    })
  })
}

Write workflow expressions in Terraform files

You can also write the definition directly in HashiCorp Configuration Language (HCL), the language of Terraform files. Terraform and Workflows both use ${...} for expressions. As a result, Terraform tries to fill in every Workflows expression in an HCL string.

To pass an expression through to Workflows, write it as $${...}. In the following example, $${inputs.who} reaches Workflows as ${inputs.who}, and var.enabled is a Terraform variable:

hcl
resource "grafana_apps_generic_resource" "hello" {
  manifest = {
    apiVersion = "workflows.ext.grafana.app/v1alpha1"
    kind       = "Definition"
    metadata = {
      name = "hello-workflow"
      annotations = {
        "grafana.app/folder" = grafana_folder.automation.uid
      }
    }
    spec = {
      name    = "Hello workflow"
      enabled = var.enabled
      startWhen = {
        matchingRules = []
        schedules     = []
      }
      steps = [
        {
          id   = "greet"
          name = "Build greeting"
          type = "transform"
          inputs = {
            template = "Hello $${inputs.who}"
          }
        }
      ]
    }
  }
}

Terraform doesn’t fill in expressions in files that you load with file, so YAML files need no changes. For workflows with many expressions, use YAML files.

Reference secrets

A workflow definition refers to a secret by its address, such as secret://..., not by its value. You can safely keep these addresses in your Terraform files and in version control.

Create the secret values in the Workflows app or in Grafana Secrets Management. For details, refer to Manage secrets.

Import a workflow into Terraform

To manage a workflow that you built in the editor, import it into Terraform. You need the workflow’s ID, which is its metadata.name. The ID appears at the end of the editor URL.

To import a workflow, follow these steps:

  1. Add a resource block whose manifest matches the workflow.

  2. Import the workflow:

    Bash
    terraform import grafana_apps_generic_resource.incident_kickoff \
      workflows.ext.grafana.app/v1alpha1/Definition/incident-kickoff

    With Terraform 1.5 or later, you can use an import block instead:

    hcl
    import {
      to = grafana_apps_generic_resource.incident_kickoff
      id = "workflows.ext.grafana.app/v1alpha1/Definition/incident-kickoff"
    }
  3. Preview the result:

    Bash
    terraform plan

    The first plan can show Terraform removing fields that Grafana adds, such as the grafana.app/createdBy annotation. These changes are safe to apply, and Grafana keeps its own fields. If the plan shows changes to spec, update your manifest until it matches the workflow.

  4. Apply the result, then run terraform plan again.

    The plan shows no changes.

Handle changes made outside Terraform

Drift is a change that someone makes to a workflow outside Terraform, for example, in the editor. When a workflow drifts, the next terraform plan shows the difference. The next terraform apply replaces the change with the version in your Terraform files.

The provider marks each workflow it creates with the grafana.app/managedBy: terraform annotation. The Workflows app doesn’t read this annotation, so it doesn’t stop edits in the editor. The provider’s allow_ui_updates argument doesn’t change this. Terraform overwrites those edits on the next apply.

Other tools do read the annotation. For example, gcx skips Terraform-managed workflows unless you add --include-managed.

To keep Terraform as the only way to change a workflow, follow these guidelines:

  • Put Terraform-managed workflows in their own Grafana folder.
  • Give most people view access to that folder. Give edit access only to the Terraform service account and the people who maintain it.
  • Run terraform plan on a schedule to find drift early.

Next steps