Grafana Cloud
Last reviewed: March 30, 2026

Use CEL expressions

Note

Grafana Workflows is currently in private preview. Grafana Labs offers support on a best-effort basis, and breaking changes might occur prior to the feature being made generally available.

Grafana Workflows uses the Common Expression Language (CEL) for dynamic values, conditions, and data transformation. CEL expressions let you reference event data, access outputs from previous steps, write conditional logic, and build dynamic content throughout your workflow.

Understand the workflow context

The workflow context is the data environment available to every step. It contains three top-level objects that you can reference in CEL expressions:

  • inputs: The event data that triggered the workflow.
  • steps: The outputs from each previously executed step, keyed by step ID.
  • resources: Resolved resource values, including decrypted secrets, loaded incident data, and loaded alert group data.

Each step can read from the context and writes its outputs back to the context for later steps to use.

Embed expressions in step inputs

Embed CEL expressions in step input values using ${expression} syntax:

YAML
inputs:
  messageText: "Incident ${inputs.data.incidentID} has severity ${inputs.data.severity}"

You can mix literal text with multiple expressions in a single field. The engine evaluates each expression and substitutes the result into the string.

To include a literal ${ in the output, escape it with $${:

YAML
inputs:
  template: "Use $${variable} for shell variables"

Access event data

When an event triggers a workflow, the event payload is available through inputs. The fields depend on the event source.

For example, to use the incident ID from a triggering event in an HTTP request:

YAML
inputs:
  url: "https://api.example.com/incidents/${inputs.data.incidentID}"

Access step outputs

Each step stores its outputs under steps.{step-id}.outputs. Later steps can reference these values to chain actions together.

The following example fetches data from an API and posts the response to Slack:

YAML
steps:
  - id: fetch-data
    type: http.call
    inputs:
      method: "GET"
      url: "https://api.example.com/data"

  - id: post-results
    type: slack.message.post
    inputs:
      channelID: "C0123456789"
      messageText: "API returned: ${steps.fetch-data.outputs.responseBody}"

When a step ID contains hyphens, use bracket notation:

text
${steps['fetch-data'].outputs.responseBody}

For details on the outputs each step type produces, refer to Step types reference.

Access incident and alert group data

Workflows that trigger on incident events automatically load the full incident into the context at resources.incident.event. Similarly, workflows triggered by alert group events automatically load the alert group at resources.alertgroup.event. You can also declare additional resources in the resources.incidents or resources.alertgroups sections of the definition.

YAML
inputs:
  message: "Incident ${resources.incident.event.title} is ${resources.incident.event.status}"
  severity: "${resources.incident.event.severity}"

For alert groups:

YAML
inputs:
  message: "Alert group ${resources.alertgroup.event.title} is ${resources.alertgroup.event.state}"
  count: "${resources.alertgroup.event.alerts_count}"

For workflows with explicitly declared resources, use the reference name you defined:

YAML
inputs:
  relatedTitle: "${resources.incident.related.title}"
  alertGroupState: "${resources.alertgroup.current.state}"

For details on declaring resources, refer to Load incident data and Load alert group data.

Write conditions

CEL supports standard comparison and logical operators for use in filter steps and switch branch conditions:

text
inputs.data.severity == "critical"
inputs.data.count > 10
inputs.data.status == "active" && inputs.data.priority == "high"
inputs.data.region == "us" || inputs.data.region == "eu"

A filter step evaluates a condition and stops the workflow if the result is false. A switch step evaluates branch conditions in order and runs the first matching branch.

For details on how to use filter and switch steps, refer to Create workflows.

Use built-in functions

Workflows extends CEL with custom functions for working with JSON data:

FunctionDescriptionExample
json_parse(string)Parse a JSON string into a structured objectjson_parse(steps.api.outputs.responseBody).name
json_stringify(value)Convert a value to a JSON stringjson_stringify(inputs.data)

Standard CEL string functions are also available, including contains, startsWith, endsWith, matches, and size.

Handle type conversions

JSON numbers deserialize as floating-point values. The CEL environment automatically converts whole-number floats to integers, so expressions like inputs.data.count > 10 work without explicit type conversion. Cross-type numeric comparisons are enabled.

Next steps