GitHub Actions Tutorial — String Functions

2 minute read

String & Type Functions

GitHub Actions provides built-in functions for string manipulation, type checking, and data conversion. These are used inside expressions to build dynamic workflows.


String Functions

contains()

Checks if a string contains a substring (case-insensitive):


if: contains(github.event.head_commit.message, '[skip ci]')

if: contains(github.event.pull_request.labels.*.name, 'urgent')

startsWith()


if: startsWith(github.ref, 'refs/tags/v')

endsWith()


if: endsWith(github.repository, '-private')

format()

String formatting with positional placeholders:


steps:
  - run: echo "${{ format('Hello {0}, welcome to {1}!', github.actor, github.repository) }}"

Output: Hello octocat, welcome to my-org/my-repo!

Use {{ and }} to escape literal braces in format strings:


${{ format('JSON: {{"key": "{0}"}}', 'value') }}

join()

Join array elements into a string:


${{ join(github.event.pull_request.labels.*.name, ', ') }}

Output: bug, enhancement, priority


Type Functions

toJSON()

Convert a value to a formatted JSON string. Useful for debugging context objects:


steps:
  - name: Dump github context
    run: echo '${{ toJSON(github) }}'

  - name: Dump matrix
    run: echo '${{ toJSON(matrix) }}'

fromJSON()

Parse a JSON string into an object:


steps:
  - name: Parse JSON output
    id: data
    run: echo 'config={"deploy":true,"env":"prod"}' >> "$GITHUB_OUTPUT"

  - name: Use parsed value
    if: fromJSON(steps.data.outputs.config).deploy == true
    run: echo "Deploying to ${{ fromJSON(steps.data.outputs.config).env }}"

Dynamic Matrix with fromJSON()


jobs:
  setup:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set.outputs.matrix }}
    steps:
      - id: set
        run: echo 'matrix={"os":["ubuntu-latest","windows-latest"],"node":[18,20]}' >> "$GITHUB_OUTPUT"

  build:
    needs: setup
    strategy:
      matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
    runs-on: ${{ matrix.os }}
    steps:
      - run: echo "OS=${{ matrix.os }}, Node=${{ matrix.node }}"

hashFiles()

Generate a SHA-256 hash of files — commonly used for cache keys:


- uses: actions/cache@v4
  with:
    path: node_modules
    key: node-${{ runner.os }}-${{ hashFiles('package-lock.json') }}

hashFiles() accepts glob patterns:


${{ hashFiles('**/package-lock.json') }}    # all package-lock files
${{ hashFiles('**/*.go', 'go.sum') }}       # Go source + dependencies


Function Reference

Function Purpose Example
contains(search, item) Substring check contains(msg, '[skip]')
startsWith(str, prefix) Prefix check startsWith(ref, 'refs/tags/')
endsWith(str, suffix) Suffix check endsWith(repo, '-dev')
format(fmt, args...) String formatting format('{0}-{1}', os, node)
join(array, sep) Join array join(labels.*.name, ',')
toJSON(value) Convert to JSON string toJSON(github)
fromJSON(str) Parse JSON string fromJSON(output)
hashFiles(patterns...) SHA-256 hash of files hashFiles('**/lock*')

Common Mistakes

Mistake Fix
contains() is case-sensitive for arrays contains() is case-insensitive for strings, but array matching depends on exact value
fromJSON() fails on invalid JSON Ensure the string is valid JSON before parsing
hashFiles() returns empty string No files matched the glob pattern — check the pattern
Using format() with unescaped braces Use {{ and }} to escape literal braces

Quick Reference

Category Functions
String contains(), startsWith(), endsWith(), format(), join()
Type toJSON(), fromJSON()
Hashing hashFiles()
Status success(), failure(), always(), cancelled()

← Previous: Status Functions

Next: Practice Exercises →

Updated: