---
title: "Create workflows | Grafana Cloud documentation"
description: "Learn how to create and edit Grafana Workflows using the visual editor or YAML definitions, including adding steps, configuring fields, and defining branches."
---

> For a curated documentation index, see [llms.txt](/llms.txt). For the complete documentation index, see [llms-full.txt](/llms-full.txt).

# Create workflows

> Note
> 
> Grafana Workflows is currently in [public preview](/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available.

You can create and edit workflows using the visual editor in the Grafana UI. This page covers the editor and the structure of a workflow definition, including how to add steps, configure fields, and define conditional branches. To write definitions in YAML or JSON and apply them from outside the editor, refer to [Manage workflows as code](/docs/grafana-cloud/platform/workflows/as-code).

## Before you begin

To create workflows, you need:

- A Grafana Cloud account with Workflows enabled for your stack
- Familiarity with the available [step types](/docs/grafana-cloud/platform/workflows/reference) and [trigger options](/docs/grafana-cloud/platform/workflows/configure-triggers)

## Create a workflow in the editor

The workflow editor provides a visual canvas for building workflows. The editor has three areas: a tree canvas on the left that shows the workflow structure, a configuration panel on the right for editing the selected node, and a header with controls for saving, running, and enabling the workflow.

### Choose a trigger

When you create a new workflow, the first step is to choose a trigger. The editor presents three options:

- **Event**: React to an event, for example, **Incident Updated**, or to events that match a regular expression, for example, `grafana_irm_app\.incident\.updated`.
- **Schedule**: Run on a cron schedule, for example, `0 9 * * 1-5` for weekdays at 9:00 AM UTC.
- **Manual**: Trigger the workflow from the editor.

Select a trigger type and configure its settings in the configuration panel. For details on trigger options, refer to [Configure triggers](/docs/grafana-cloud/platform/workflows/configure-triggers).

### Add steps

To add a step to your workflow:

1. Click **+** on the last node in the tree.
2. Browse or search the action palette that appears in the configuration panel.
3. Click a step type or drag it onto the drop zone.

The new step appears in the tree and the configuration panel displays its configuration form. Fill in the required fields for the step type you selected.

For a full list of available step types and their inputs, refer to [Step and trigger types reference](/docs/grafana-cloud/platform/workflows/reference).

### Configure step fields

The configuration panel renders form fields based on the step type. Field types include text inputs, text areas for longer content like message bodies, checkboxes for boolean values, dropdowns for constrained choices like HTTP methods, and JSON editors for structured data.

Fields that accept string values can include CEL expressions using `${expression}` syntax to reference the workflow context. For example, you can set a URL field to `https://api.example.com/incidents/${inputs.data.incidentID}` to include the incident ID from the triggering event.

For details on expressions and the workflow context, refer to [Use CEL expressions](/docs/grafana-cloud/platform/workflows/use-expressions).

### Add conditional logic

To add conditional branching:

1. Add a **Switch** step from the action palette.
2. The switch node appears in the tree. Click **+** on it to add condition branches.
3. Select each condition node and enter a CEL expression in the configuration panel, for example, `resources.incident.event.severity.matches('(?i)^critical$')`.
4. Add steps inside each condition branch by clicking **+** on the condition node.
5. Leave exactly one branch without a condition expression. Every switch needs this default case.

After all branches have at least one step, a down-arrow appears on the switch node. Click it to add continuation steps that run after the switch completes, regardless of which branch ran.

For the field-by-field schema, refer to [Switch step](/docs/grafana-cloud/platform/workflows/reference/#switch-switch).

### Run a workflow on demand

**Run** is available after you save the workflow for the first time and turn on **Enable**. It runs the workflow as it’s shown in the editor, including unsaved changes. Turning **Enable** on or off isn’t kept until you click **Save**.

Click **Run** in the editor header to trigger the workflow with a sample event. The **Trigger Workflow** dialog box opens with a sample event in [CloudEvents](https://cloudevents.io/) shape. Edit the JSON as needed, or choose a different sample in **Example Event** if the list appears, then click **Trigger Workflow**.

The fields under `data` become available in your steps as `inputs.data.*`. The other fields (`id`, `type`, `source`, `time`) describe the event itself. To inspect the run, click the arrow next to **Run** to open the **Latest runs** panel.

> Note
> 
> **Run** doesn’t load incident or alert group data from the sample event, and it doesn’t apply trigger filters. To test a workflow that uses that data, add the incident or alert group as a resource. For details, refer to [Test with incident data](/docs/grafana-cloud/platform/workflows/load-incident-data/#test-with-incident-data) and [Test with alert group data](/docs/grafana-cloud/platform/workflows/load-alert-group-data/#test-with-alert-group-data).

For details, refer to [Trigger workflows manually](/docs/grafana-cloud/platform/workflows/configure-triggers/#trigger-workflows-manually).

### View the JSON definition

Open the **More** menu in the editor header and select **View JSON** to open a read-only drawer showing the workflow definition as JSON. This view is useful for reviewing the full structure or copying the definition for use in version control.

## Write a workflow definition

Every workflow is stored as a definition that you can read as YAML or JSON. Working with definitions directly is useful for review, version control, and keeping a record of a workflow outside of Grafana.

The editor in the Workflows app is visual only. To read a workflow’s definition there, use **View JSON**.

To create and update definitions outside the Workflows app, with an AI agent, the gcx CLI, the API, or Terraform, refer to [Manage workflows as code](/docs/grafana-cloud/platform/workflows/as-code).

### Understand the definition structure

Workflow definitions are Grafana resources in the `workflows.ext.grafana.app` API group. The following example shows the top-level structure of a definition:

YAML ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```yaml
apiVersion: workflows.ext.grafana.app/v1alpha1
kind: Definition
metadata:
  name: my-workflow
  namespace: my-namespace
  annotations:
    grafana.app/folder: <FOLDER_UID>
spec:
  name: 'My Workflow'
  enabled: true
  startWhen:
    matchingRules: []
    schedules: []
  steps: []
  resources:
    secrets: {}
    incidents: {}
    alertgroups: {}
  runOnceFor: ''
```

The `metadata` fields identify the workflow and place it in a folder:

- `name`: The unique identifier for the definition within its namespace. Use lowercase letters, numbers, and hyphens. This is separate from `spec.name`, which is the display name.
- `namespace`: The namespace for your Grafana Cloud stack, in the form `stacks-<STACK_ID>`.
- `annotations.grafana.app/folder`: The UID of the folder that holds the workflow. This annotation is required. For details, refer to [Place a workflow in a folder](#place-a-workflow-in-a-folder).

The `spec` fields describe the workflow itself:

- `name`: A human-readable name for the workflow.
- `enabled`: When `true`, the workflow runs automatically when its trigger conditions are met. When `false`, the workflow doesn’t run on events or schedules, and **Run** in the editor is unavailable.
- `startWhen`: Defines the trigger conditions. Contains `matchingRules` for event triggers and `schedules` for cron triggers. For details, refer to [Configure triggers](/docs/grafana-cloud/platform/workflows/configure-triggers).
- `steps`: An ordered list of steps that run in order.
- `resources.secrets`: An optional map of reference names to secret URIs for authentication. For details, refer to [Manage secrets](/docs/grafana-cloud/platform/workflows/manage-secrets).
- `resources.incidents`: An optional map of reference names to incident URIs in the form `incident://id/<INCIDENT_ID>`. Write the URI as a literal or build it with `${...}`, for example, `incident://id/${inputs.data.incidentID}`. For details, refer to [Load incident data](/docs/grafana-cloud/platform/workflows/load-incident-data).
- `resources.alertgroups`: An optional map of reference names to alert group URIs in the form `alertgroup://id/<ALERT_GROUP_ID>`. Write the URI as a literal or build it with `${...}`. For details, refer to [Load alert group data](/docs/grafana-cloud/platform/workflows/load-alert-group-data).
- `runOnceFor`: An optional template string for deduplication. Use `${...}` segments for CEL expressions. For details, refer to [Configure triggers](/docs/grafana-cloud/platform/workflows/configure-triggers).

> Note
> 
> To declare secrets, incidents, and alert groups in the editor, open the **More** menu, select **Settings**, and use the **Resources** tab.

### Place a workflow in a folder

Every workflow belongs to a Grafana folder. The folder is recorded in the `grafana.app/folder` annotation as a folder UID, and it determines who can read and edit the workflow. For details on how folder permissions combine with the Workflows roles, refer to [Manage access](/docs/grafana-cloud/platform/workflows/manage-access).

YAML ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```yaml
metadata:
  name: my-workflow
  annotations:
    grafana.app/folder: bfuxhb5uqiv40c
```

The annotation is required. Saving a definition without it fails with the following message:

![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```none
annotation "grafana.app/folder" is required and must be non-empty
```

The editor handles this for you. When you save a workflow that has no folder yet, a **Select a folder** dialog box opens so you can choose a folder for the workflow. You can move a workflow later from the **Settings** drawer in the editor. The workflow list, which opens from **Manage workflows**, shows each workflow’s folder and lets you filter by it.

To find a folder’s UID, open the folder in Grafana and copy the UID from the page URL, which has the form `/dashboards/f/<FOLDER_UID>/`.

> Note
> 
> If a workflow shows no folder, open it, choose a folder, and save it.

### Define steps

Each step requires a `type`, an `id`, and typically a set of `inputs`:

YAML ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```yaml
steps:
  - id: call-api
    type: http.call
    name: 'Fetch incident details'
    inputs:
      method: 'GET'
      url: 'https://api.example.com/incidents/${inputs.data.incidentID}'
```

Step IDs must start with a lowercase letter and can contain lowercase letters, numbers, hyphens, and underscores. In the editor, step IDs also need at least 5 characters.

### Disable a step

You can disable individual steps to skip them during execution without removing them from the workflow. This is useful when you want to temporarily bypass a step while testing or debugging.

To disable a step in the editor, select the step and toggle **Enable** off in the configuration panel. The step appears dimmed on the canvas and Workflows skips it when the workflow runs.

In a YAML definition, set `disabled: true` on the step:

YAML ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```yaml
steps:
  - id: call-api
    type: http.call
    disabled: true
    name: 'Fetch incident details'
    inputs:
      method: 'GET'
      url: 'https://api.example.com/incidents/${inputs.data.incidentID}'
```

When you disable a switch step, all of its condition branches are also skipped. Other steps in the workflow can’t reference outputs from a disabled step. If an enabled step references a disabled step’s outputs, it causes a validation error when you save the workflow.

To re-enable the step, toggle **Enable** on or remove the `disabled` field from the YAML.

### Run custom code

Use the `code.execute` step to run sandboxed Python code. Your code can read a `context` variable with the workflow context (trigger inputs, previous step outputs, and loaded resources) and an `args` variable with any named arguments you define. The `context` variable never includes secrets.

YAML ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```yaml
steps:
  - id: fetch-data
    type: http.call
    name: 'Fetch incident data'
    inputs:
      method: 'GET'
      url: 'https://api.example.com/incidents/${inputs.data.incidentID}'

  - id: process-incident
    type: code.execute
    name: 'Summarize incident'
    inputs:
      language: python
      code: |
        import json

        response = json.loads(context["steps"]["fetch-data"]["outputs"]["responseBody"])
        labels = response.get("labels", [])
        severity = args.get("default_severity", "unknown")

        for label in labels:
            if label.startswith("severity/"):
                severity = label.split("/")[1]

        print(json.dumps({
            "title": response["title"],
            "severity": severity,
            "label_count": len(labels),
        }))
      args: '{"default_severity": "${resources.incident.event.severity}"}'

  - id: post-summary
    type: slack.message.post
    inputs:
      channelID: 'C0123456789'
      messageText: "Incident summary: ${steps['process-incident'].outputs.stdout}"
```

The code step captures `stdout` as its primary output. Write structured data as JSON to stdout so later steps can reference it. `stderr` is available separately for diagnostics.

A Python exception doesn’t fail the step. The step completes with `success: false`, and the run continues. To stop the run when the code fails, add a filter step after it with the condition `steps['process-incident'].outputs.success == true` and `failOnExit: "true"`.

For the full list of inputs, outputs, and the `context` variable structure, refer to [Execute code](/docs/grafana-cloud/platform/workflows/reference/#execute-code-codeexecute) in the step types reference.

### Define branches

Use the `switch` step type with `branches` to add conditional logic. The following example runs on an incident trigger and routes on the severity of the incident that Workflows loads as `resources.incident.event`:

YAML ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```yaml
steps:
  - id: route-by-severity
    type: switch
    branches:
      - condition: "resources.incident.event.severity.matches('(?i)^critical$')"
        steps:
          - id: page-oncall
            type: irm.page-user
            inputs:
              userID: "oncall@example.com"
              important: "true"
              message: "Critical incident: ${resources.incident.event.title}"
      - condition: "resources.incident.event.severity.matches('(?i)^major$')"
        steps:
          - id: notify-channel
            type: slack.message.post
            inputs:
              channelID: 'C0123456789'
              messageText: 'Major incident: ${resources.incident.event.title}'
      - steps:
          - id: log-event
            type: transform
            inputs:
              template: 'Non-actionable severity: ${resources.incident.event.severity}'
```

Branches evaluate in order. The first branch whose condition evaluates to `true` runs. Every switch needs exactly one branch with no `condition` field, which acts as the default case. You can nest a switch step inside a branch for more routing.

Incident severity holds the severity’s display label, for example, `Critical`, so the example compares it without regard to case.

For the field-by-field schema, refer to [Switch step](/docs/grafana-cloud/platform/workflows/reference/#switch-switch).

## Next steps

- [Configure triggers](/docs/grafana-cloud/platform/workflows/configure-triggers)
- [Use CEL expressions](/docs/grafana-cloud/platform/workflows/use-expressions)
- [Load incident data](/docs/grafana-cloud/platform/workflows/load-incident-data)
- [Load alert group data](/docs/grafana-cloud/platform/workflows/load-alert-group-data)
- [Manage secrets](/docs/grafana-cloud/platform/workflows/manage-secrets)
- [Step and trigger types reference](/docs/grafana-cloud/platform/workflows/reference)
