Writing a good condition in GitHub workflows

Conditions are used to control job or step execution and are defined by if
YAML key like this:
jobs:
first-job:
if: ${{ github.event_name == 'workflow_dispatch' }} #<---- conditions
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
There are a few specifics that might not be obvious at first.
For example, I was used to always writing those opening and closing ${{
/ }}
without realizing I don’t really need them in most cases.
From the documentation mentioned above:
When you use expressions in an
if
conditional, you can, optionally, omit the${{ }}
expression syntax because GitHub Actions automatically evaluates theif
conditional as an expression. However, this exception does not apply everywhere.You must always use the
${{ }}
expression syntax or escape with''
,""
, or()
when the expression starts with!
, since!
is reserved notation in YAML format.
That means this won’t work:
- name: worng syntax condition
if: !startsWith(inputs.first_name, 'X') #<--- this won't work
shell: bash
run: |
echo 'wrong syntax'
The YAML parser will start complaining, so you won't even be able to start the workflow.
To get around it, you have to use ${{
/ }}
, or escape it just like the documentation says.
# enclosed in parenthesis
- name: ok condition
if: (!startsWith(inputs.first_name, 'X')) #<--- ok now!
shell: bash
run: |
echo 'ok now'
# escaped with double quotes " "
- name: ok condition
if: "!startsWith(inputs.first_name, 'X')" #<--- ok now!
shell: bash
run: |
echo 'ok now'
# escaped with single quotes ' '
- name: ok condition
if: '!startsWith(inputs.first_name, ''X'')' #<--- ok now!
# any exiting quotes have to be escaped ↑ ↑ with one extra '
shell: bash
run: |
echo 'ok now'
Another annoying thing is how large some conditions can grow in complex workflows. They can easily be more than 80 characters long and hard to read:
- name: long condition
if: fromJSON(steps.vars.outputs.custom_json).key == 'value' && (inputs.first_name == 'John' || inputs.last_name == 'Doe') && github.event_name == 'workflow_dispatch'
shell: bash
run: |
echo 'multiline condition' >> $GITHUB_STEP_SUMMARY
One neat trick to keep conditions readable (and rows short) is to switch to multiline YAML strings:
- name: multiline condition
if: |
fromJSON(steps.vars.outputs.custom_json).key == 'value' &&
(
inputs.first_name == 'John' ||
inputs.last_name == 'Doe'
) &&
github.event_name == 'workflow_dispatch'
shell: bash
run: |
echo ''
echo 'multiline condition' >> $GITHUB_STEP_SUMMARY
One thing to watch for here is that you can’t start any single condition with !
as you might be used to from other programming languages. This is not a valid condition, for example:
- name: ivalid multiline condition
if: |
inputs.first_name == 'John' &&
!inputs.last_name == 'Doe'
But this works fine:
- name: ivalid multiline condition
if: |
inputs.first_name == 'John' &&
!(inputs.last_name == 'Doe')
Conclusion
Conditions in GitHub workflows and/or actions can easily become long and complex. Luckily, it is easy to format them as you wish using multiline YAML strings with |
indicator.
That is all for now. Thank you. 👋
Happy coding :)
Subscribe to my newsletter
Read articles from Juraj Simon directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Juraj Simon
Juraj Simon
DevOps/FullStack node.js developer. Passionate about automation and efficiency. Learning how to write... :)