If
The if step evaluates a boolean or Kibana Query Language (KQL) expression and runs different steps based on whether the condition is true or false.
Use the following parameters to configure an if step:
| Parameter | Required | Description |
|---|---|---|
name |
Yes | Unique step identifier |
type |
Yes | Step type - must be if |
condition |
Yes | A boolean or KQL expression to evaluate |
steps |
Yes | An array of steps to run if the condition is true |
else |
No | An array of steps to run if the condition is false |
steps:
- name: conditionalStep
type: if
condition: <boolean or KQL expression>
steps:
# Steps to run if condition is true
else:
# Steps to run if condition is false (optional)
if on that step. Refer to Skip a single step.
The condition field supports the following expression types:
Use ${{ }} syntax when you want the expression to evaluate directly to a boolean value:
steps:
- name: check-enabled
type: if
condition: "${{ inputs.isEnabled }}"
steps:
- name: process-enabled
type: http
else:
- name: log-disabled
type: console
If the expression evaluates to undefined, it defaults to false.
Use a string-based condition to evaluate the value as a KQL expression. You can use {{ }} templating to inject dynamic values:
steps:
- name: check-status
type: if
condition: "{{ steps.fetchData.output.status }}: completed"
steps:
- name: process-data
type: http
The if step supports the following KQL features:
condition: "status: active"
condition: "user.role: admin"
condition: "isActive: true"
condition: "count: 42"
condition: "users[0].name: Alice"
- Array index access
condition: "count >= 100"
condition: "count <= 1000"
condition: "count > 50"
condition: "count < 200"
condition: "count >= 100 and count <= 1000"
condition: "fieldName:*"
condition: "user.name: John*"
condition: "user.name: *Doe"
condition: "txt: *ipsum*"
condition: "user.name: J*n Doe"
- Field exists
- Starts with
- Ends with
- Contains
- Pattern
condition: "status: active and isEnabled: true"
condition: "status: active or status: pending"
condition: "not status: inactive"
condition: "status: active and (role: admin or role: moderator)"
- And
- Or
- Not
- Nested
condition: "user.info.name: John Doe"
condition: "steps.fetchData.output.status: completed"
condition: "users[0].name: Alice"
condition: "users.0.name: Alice"
- Nested property
- Deep nesting
- Array access
- Alternative syntax
This example runs different steps based on the event severity:
steps:
- name: checkSeverity
type: if
condition: "event.severity: 'critical'"
steps:
- name: handleCritical
type: console
with:
message: "Critical alert!"
else:
- name: handleNormal
type: console
with:
message: "Normal severity"
You can write the same check as a boolean expression with ${{ }} syntax, for example condition: "${{ event.severity == 'critical' }}".
This example checks the number of search results and processes them differently based on the count:
name: National Parks Conditional Processing
steps:
- name: searchParks
type: elasticsearch.search
with:
index: national-parks-index
size: 100
- name: checkResultCount
type: if
condition: "steps.searchParks.output.hits.total.value > 5"
steps:
- name: processLargeDataset
type: foreach
foreach: "{{ steps.searchParks.output.hits.hits }}"
steps:
- name: processPark
type: console
with:
message: "Processing park: {{ foreach.item._source.title }}"
else:
- name: handleSmallDataset
type: console
with:
message: "Only {{ steps.searchParks.output.hits.total.value }} parks found - manual review needed"
This example uses multiple logical operators to check a combination of conditions:
steps:
- name: check-complex
type: if
condition: "status: active and (count >= 100 or role: admin)"
steps:
- name: process-authorized
type: http
When only one step in a workflow is optional, you don't need a separate if step to control it. Instead, set if directly on that step. This step-level if makes the step run only when its condition is true. When the condition is false, the workflow skips the step and continues with the next one.
For example, the following snippets both run a notify step only when an earlier search step, find_failed_logins, finds at least one match. The first snippet wraps notify in an if step:
- name: check_results
type: if
condition: "steps.find_failed_logins.output.hits.total.value > 0"
steps:
- name: notify
type: console
with:
message: "Found {{ steps.find_failed_logins.output.hits.total.value }} failed logins."
The second snippet sets a step-level if on notify. The result is the same, with one fewer step and one fewer level of nesting:
- name: notify
type: console
if: "steps.find_failed_logins.output.hits.total.value > 0"
with:
message: "Found {{ steps.find_failed_logins.output.hits.total.value }} failed logins."
Use an if step instead when you need an else branch for the false case, or when one condition controls several steps.
A step-level if accepts the same boolean and KQL expressions as the if step's condition.
A skipped step doesn't produce output, so a later reference such as {{ steps.notify.output }} resolves to an empty value. If a later step depends on the skipped step's output, set the same condition on that step too.
A step-level if causes a validation error in the following cases. Each case has an alternative that you can use instead.
An if step already uses condition to decide what runs, so it can't also have a step-level if. For example, an if step can't have both condition: "status: active" and if: "inputs.enabled: true".
Instead, combine both checks in condition with and, for example condition: "status: active and inputs.enabled: true".
Steps inside a parallel branch can't have a step-level if, so a branch can't skip individual steps. For example, you can't skip a GeoIP lookup in one branch when an alert has no source IP.
To run or skip all branches at once, add if to the parallel step instead, for example if: "inputs.enrich: true". To skip steps in only one branch, move those steps into a child workflow, add if to them there, and call the child workflow from the branch with workflow.execute.
For more about what a branch can contain, refer to Branch body limitations.
A step-level if and an if step's condition can each be up to 2,000 characters long. You might reach this limit with a check that lists hundreds of host names joined with or.
Instead, move the long part out of the condition. For example, store the host names as a list in consts, then check the list with if: "${{ consts.watched_hosts contains inputs.host_name }}". You can also calculate a value in an earlier data.set step and check that value instead.