Skip to main content

Evaluate expressions in workflows and actions

You can evaluate expressions in workflows and actions.

About expressions

You can use expressions to programmatically set environment variables in workflow files and access contexts. An expression can be any combination of literal values, references to a context, or functions. You can combine literals, context references, and functions using operators. For more information about contexts, see "Accessing contextual information about workflow runs."

Expressions are commonly used with the conditionalifkeyword in a workflow file to determine whether a step should run. When anifconditional istrue,the step will run.

You need to use specific syntax to tell GitHub to evaluate an expression rather than treat it as a string.

${{ <expression> }}

Note:The exception to this rule is when you are using expressions in anifclause, where, optionally, you can usually omit${{and}}.For more information aboutifconditionals, see "Workflow syntax for GitHub Actions."

Warning:When creating workflows and actions, you should always consider whether your code might execute untrusted input from possible attackers. Certain contexts should be treated as untrusted input, as an attacker could insert their own malicious content. For more information, see "Security hardening for GitHub Actions."

Example setting an environment variable

env:
MY_ENV_VAR:${{<expression>}}

Literals

As part of an expression, you can useboolean,null,number,orstringdata types.

Data typeLiteral value
booleantrueorfalse
nullnull
numberAny number format supported by JSON.
stringYou don't need to enclose strings in${{and}}.However, if you do, you must use single quotes (') around the string. To use a literal single quote, escape the literal single quote using an additional single quote (''). Wrapping with double quotes (") will throw an error.

Note that in conditionals, falsy values (false,0,-0,"",'',null) are coerced tofalseand truthy (trueand other non-falsy values) are coerced totrue.

Example of literals

env:
myNull:${{null}}
myBoolean:${{false}}
myIntegerNumber:${{711}}
myFloatNumber:${{-9.2}}
myHexNumber:${{0xff}}
myExponentialNumber:${{-2.99e-2}}
myString:MonatheOctocat
myStringInBraces:${{'It''s open source!'}}

Operators

OperatorDescription
( )Logical grouping
[ ]Index
.Property de-reference
!Not
<Less than
<=Less than or equal
>Greater than
>=Greater than or equal
==Equal
!=Not equal
&&And
||Or

Notes:

  • GitHub ignores case when comparing strings.
  • steps.<step_id>.outputs.<output_name>evaluates as a string. You need to use specific syntax to tell GitHub to evaluate an expression rather than treat it as a string. For more information, see "Accessing contextual information about workflow runs."
  • For numerical comparison, thefromJSON()function can be used to convert a string to a number. For more information on thefromJSON()function, see "fromJSON."

GitHub performs loose equality comparisons.

  • If the types do not match, GitHub coerces the type to a number. GitHub casts data types to a number using these conversions:

    TypeResult
    Null0
    Booleantruereturns1
    falsereturns0
    StringParsed from any legal JSON number format, otherwiseNaN.
    Note: empty string returns0.
    ArrayNaN
    ObjectNaN
  • WhenNaNis one of the operands of any relational comparison (>,<,>=,<=), the result is alwaysfalse.For more information, see the "NaN Mozilla docs."

  • GitHub ignores case when comparing strings.

  • Objects and arrays are only considered equal when they are the same instance.

GitHub offers ternary operator like behaviour that you can use in expressions. By using a ternary operator in this way, you can dynamically set the value of an environment variable based on a condition, without having to write separate if-else blocks for each possible option.

Example

env:
MY_ENV_VAR:${{github.ref=='refs/heads/main'&&'value_for_main_branch'||'value_for_other_branches'}}

In this example, we're using a ternary operator to set the value of theMY_ENV_VARenvironment variable based on whether the GitHub reference is set torefs/heads/mainor not. If it is, the variable is set tovalue_for_main_branch.Otherwise, it is set tovalue_for_other_branches. It is important to note that the first value after the&&must be truthy. Otherwise, the value after the||will always be returned.

Functions

GitHub offers a set of built-in functions that you can use in expressions. Some functions cast values to a string to perform comparisons. GitHub casts data types to a string using these conversions:

TypeResult
Null''
Boolean'true'or'false'
NumberDecimal format, exponential for large numbers
ArrayArrays are not converted to a string
ObjectObjects are not converted to a string

contains

contains( search, item )

Returnstrueifsearchcontainsitem.Ifsearchis an array, this function returnstrueif theitemis an element in the array. Ifsearchis a string, this function returnstrueif theitemis a substring ofsearch.This function is not case sensitive. Casts values to a string.

Example using a string

contains('Hello world', 'llo')returnstrue.

Example using an object filter

contains(github.event.issue.labels.*.name, 'bug')returnstrueif the issue related to the event has a label "bug".

For more information, see "Object filters."

Example matching an array of strings

Instead of writinggithub.event_name == "push" || github.event_name == "pull_request",you can usecontains()withfromJSON()to check if an array of strings contains anitem.

For example,contains(fromJSON('[ "push", "pull_request" ]'), github.event_name)returnstrueifgithub.event_nameis "push" or "pull_request".

startsWith

startsWith( searchString, searchValue )

ReturnstruewhensearchStringstarts withsearchValue.This function is not case sensitive. Casts values to a string.

Example ofstartsWith

startsWith('Hello world', 'He')returnstrue.

endsWith

endsWith( searchString, searchValue )

ReturnstrueifsearchStringends withsearchValue.This function is not case sensitive. Casts values to a string.

Example ofendsWith

endsWith('Hello world', 'ld')returnstrue.

format

format( string, replaceValue0, replaceValue1,..., replaceValueN)

Replaces values in thestring,with the variablereplaceValueN.Variables in thestringare specified using the{N}syntax, whereNis an integer. You must specify at least onereplaceValueandstring.There is no maximum for the number of variables (replaceValueN) you can use. Escape curly braces using double braces.

Example offormat

format('Hello {0} {1} {2}','Mona','the','Octocat')

Returns 'Hello Mona the Octocat'.

Example escaping braces

format('{{Hello {0} {1} {2}!}}','Mona','the','Octocat')

Returns '{Hello Mona the Octocat!}'.

join

join( array, optionalSeparator )

The value forarraycan be an array or a string. All values inarrayare concatenated into a string. If you provideoptionalSeparator,it is inserted between the concatenated values. Otherwise, the default separator,is used. Casts values to a string.

Example ofjoin

join(github.event.issue.labels.*.name, ', ')may return 'bug, help wanted'

toJSON

toJSON(value)

Returns a pretty-print JSON representation ofvalue.You can use this function to debug the information provided in contexts.

Example oftoJSON

toJSON(job)might return{ "status": "success" }

fromJSON

fromJSON(value)

Returns a JSON object or JSON data type forvalue.You can use this function to provide a JSON object as an evaluated expression or to convert any data type that can be represented in JSON or JavaScript, such as strings, booleans, null values, arrays, and objects.

Example returning a JSON object

This workflow sets a JSON matrix in one job, and passes it to the next job using an output andfromJSON.

YAML
name:build
on:push
jobs:
job1:
runs-on:ubuntu-latest
outputs:
matrix:${{steps.set-matrix.outputs.matrix}}
steps:
-id:set-matrix
run:echo"matrix={\" include\ ":[{\" project\ ":\" foo\ ",\" config\ ":\" Debug\ "},{\" project\ ":\" bar\ ",\" config\ ":\" Release\ "}]}">>$GITHUB_OUTPUT
job2:
needs:job1
runs-on:ubuntu-latest
strategy:
matrix:${{fromJSON(needs.job1.outputs.matrix)}}
steps:
-run:echo"Matrix - Project ${{ matrix.project }},Config ${{ matrix.config }}"

Example returning a JSON data type

This workflow usesfromJSONto convert environment variables from a string to a Boolean or integer.

YAML
name:print
on:push
env:
continue:true
time:3
jobs:
job1:
runs-on:ubuntu-latest
steps:
-continue-on-error:${{fromJSON(env.continue)}}
timeout-minutes:${{fromJSON(env.time)}}
run:echo...

The workflow uses thefromJSON()function to convert the environment variablecontinuefrom a string to a boolean, allowing it to determine whether to continue-on-error or not. Similarly, it converts thetimeenvironment variable from a string to an integer, setting the timeout for the job in minutes.

hashFiles

hashFiles(path)

Returns a single hash for the set of files that matches thepathpattern. You can provide a singlepathpattern or multiplepathpatterns separated by commas. Thepathis relative to theGITHUB_WORKSPACEdirectory and can only include files inside of theGITHUB_WORKSPACE.This function calculates an individual SHA-256 hash for each matched file, and then uses those hashes to calculate a final SHA-256 hash for the set of files. If thepathpattern does not match any files, this returns an empty string. For more information about SHA-256, see "SHA-2."

You can use pattern matching characters to match file names. Pattern matching forhashFilesfollows glob pattern matching and is case-insensitive on Windows. For more information about supported pattern matching characters, see thePatternssection in the@actions/globdocumentation.

Example with a single pattern

Matches anypackage-lock.jsonfile in the repository.

hashFiles('**/package-lock.json')

Example with multiple patterns

Creates a hash for anypackage-lock.jsonandGemfile.lockfiles in the repository.

hashFiles('**/package-lock.json', '**/Gemfile.lock')

Status check functions

You can use the following status check functions as expressions inifconditionals. A default status check ofsuccess()is applied unless you include one of these functions. For more information aboutifconditionals, see "Workflow syntax for GitHub Actions"and"Metadata syntax for GitHub Actions".

success

Returnstruewhen all previous steps have succeeded.

Example ofsuccess

steps:
...
-name:Thejobhassucceeded
if:${{success()}}

always

Causes the step to always execute, and returnstrue,even when canceled. Thealwaysexpression is best used at the step level or on tasks that you expect to run even when a job is canceled. For example, you can usealwaysto send logs even when a job is canceled.

Warning:Avoid usingalwaysfor any task that could suffer from a critical failure, for example: getting sources, otherwise the workflow may hang until it times out. If you want to run a job or step regardless of its success or failure, use the recommended alternative:if: ${{!cancelled() }}

Example ofalways

if:${{always()}}

cancelled

Returnstrueif the workflow was canceled.

Example ofcancelled

if:${{cancelled()}}

failure

Returnstruewhen any previous step of a job fails. If you have a chain of dependent jobs,failure()returnstrueif any ancestor job fails.

Example offailure

steps:
...
-name:Thejobhasfailed
if:${{failure()}}

failure with conditions

You can include extra conditions for a step to run after a failure, but you must still includefailure()to override the default status check ofsuccess()that is automatically applied toifconditions that don't contain a status check function.

Example offailurewith conditions
steps:
...
-name:Failingstep
id:demo
run:exit1
-name:Thedemostephasfailed
if:${{failure()&&steps.demo.conclusion=='failure'}}

Object filters

You can use the*syntax to apply a filter and select matching items in a collection.

For example, consider an array of objects namedfruits.

[
{"name":"apple","quantity":1},
{"name":"orange","quantity":2},
{"name":"pear","quantity":1}
]

The filterfruits.*.namereturns the array[ "apple", "orange", "pear" ].

You may also use the*syntax on an object. For example, suppose you have an object namedvegetables.


{
"scallions":
{
"colors":["green","white","red"],
"ediblePortions":["roots","stalks"],
},
"beets":
{
"colors":["purple","red","gold","white","pink"],
"ediblePortions":["roots","stems","leaves"],
},
"artichokes":
{
"colors":["green","purple","red","black"],
"ediblePortions":["hearts","stems","leaves"],
},
}

The filtervegetables.*.ediblePortionscould evaluate to:


[
["roots","stalks"],
["hearts","stems","leaves"],
["roots","stems","leaves"],
]

Since objects don't preserve order, the order of the output cannot be guaranteed.