Skip to main content

Workflow commands for GitHub Actions

You can use workflow commands when running shell commands in a workflow or in an action's code.

Note: GitHub-hosted runners are not currently supported on GitHub Enterprise Server. You can see more information about planned future support on the GitHub public roadmap.

About workflow commands

Actions can communicate with the runner machine to set environment variables, output values used by other actions, add debug messages to the output logs, and other tasks.

Most workflow commands use the echo command in a specific format, while others are invoked by writing to a file. For more information, see "Environment files".

echo "::workflow-command parameter1={data},parameter2={data}::{command value}"

Note: Workflow command and parameter names are not case-sensitive.

Warning: If you are using Command Prompt, omit double quote characters (") when using workflow commands.

Using workflow commands to access toolkit functions

The actions/toolkit includes a number of functions that can be executed as workflow commands. Use the :: syntax to run the workflow commands within your YAML file; these commands are then sent to the runner over stdout. For example, instead of using code to set an output, as below:

core.setOutput('SELECTED_COLOR', 'green');

You can use the set-output command in your workflow to set the same value:

      - name: Set selected color
        run: echo '::set-output name=SELECTED_COLOR::green'
        id: random-color-generator
      - name: Get color
        run: echo "The selected color is ${{ steps.random-color-generator.outputs.SELECTED_COLOR }}"

The following table shows which toolkit functions are available within a workflow:

Toolkit functionEquivalent workflow command
core.addPathAccessible using environment file GITHUB_PATH
core.exportVariableAccessible using environment file GITHUB_ENV
core.getInputAccessible using environment variable INPUT_{NAME}
core.getStateAccessible using environment variable STATE_{NAME}
core.isDebugAccessible using environment variable RUNNER_DEBUG
core.setFailedUsed as a shortcut for ::error and exit 1

Setting an output parameter

::set-output name={name}::{value}

Sets an action's output parameter.

Optionally, you can also declare output parameters in an action's metadata file. For more information, see "Metadata syntax for GitHub Actions."


echo "::set-output name=action_fruit::strawberry"

Setting a debug message


Prints a debug message to the log. You must create a secret named ACTIONS_STEP_DEBUG with the value true to see the debug messages set by this command in the log. For more information, see "Enabling debug logging."


echo "::debug::Set the Octocat variable"

Setting a warning message

::warning file={name},line={line},endLine={endLine},title={title}::{message}

Creates a warning message and prints the message to the log. This message will create an annotation, which can associate the message with a particular file in your repository. Optionally, your message can specify a position within the file.

colColumn number, starting at 1
lineLine number, starting at 1


echo "::warning file=app.js,line=1,col=5,endColumn=7::Missing semicolon"

Setting an error message

::error file={name},line={line},endLine={endLine},title={title}::{message}

Creates an error message and prints the message to the log. This message will create an annotation, which can associate the message with a particular file in your repository. Optionally, your message can specify a position within the file.

colColumn number, starting at 1
lineLine number, starting at 1


echo "::error file=app.js,line=1,col=5,endColumn=7::Missing semicolon"

Grouping log lines


Creates an expandable group in the log. To create a group, use the group command and specify a title. Anything you print to the log between the group and endgroup commands is nested inside an expandable entry in the log.


echo "::group::My title"
echo "Inside group"
echo "::endgroup::"

Foldable group in workflow run log

Masking a value in log


Masking a value prevents a string or variable from being printed in the log. Each masked word separated by whitespace is replaced with the * character. You can use an environment variable or string for the mask's value.

Example masking a string

When you print "Mona The Octocat" in the log, you'll see "***".

echo "::add-mask::Mona The Octocat"

Example masking an environment variable

When you print the variable MY_NAME or the value "Mona The Octocat" in the log, you'll see "***" instead of "Mona The Octocat".

MY_NAME="Mona The Octocat"
echo "::add-mask::$MY_NAME"

Stopping and starting workflow commands


Stops processing any workflow commands. This special command allows you to log anything without accidentally running a workflow command. For example, you could stop logging to output an entire script that has comments.

To stop the processing of workflow commands, pass a unique token to stop-commands. To resume processing workflow commands, pass the same token that you used to stop workflow commands.

Warning: Make sure the token you're using is randomly generated and unique for each run. As demonstrated in the example below, you can generate a unique hash of your github.token for each run.


Example stopping and starting workflow commands

    runs-on: ubuntu-latest
      - name: disable workflow commands
        run: |
          echo '::warning:: this is a warning'
          echo "::stop-commands::`echo -n ${{ github.token }} | sha256sum | head -c 64`"
          echo '::warning:: this will NOT be a warning'
          echo "::`echo -n ${{ github.token }} | sha256sum | head -c 64`::"
          echo '::warning:: this is a warning again'

Echoing command outputs


Enables or disables echoing of workflow commands. For example, if you use the set-output command in a workflow, it sets an output parameter but the workflow run's log does not show the command itself. If you enable command echoing, then the log shows the command, such as ::set-output name={name}::{value}.

Command echoing is disabled by default. However, a workflow command is echoed if there are any errors processing the command.

The add-mask, debug, warning, and error commands do not support echoing because their outputs are already echoed to the log.

You can also enable command echoing globally by turning on step debug logging using the ACTIONS_STEP_DEBUG secret. For more information, see "Enabling debug logging". In contrast, the echo workflow command lets you enable command echoing at a more granular level, rather than enabling it for every workflow in a repository.

Example toggling command echoing

    runs-on: ubuntu-latest
      - name: toggle workflow command echoing
        run: |
          echo '::set-output name=action_echo::disabled'
          echo '::echo::on'
          echo '::set-output name=action_echo::enabled'
          echo '::echo::off'
          echo '::set-output name=action_echo::disabled'

The step above prints the following lines to the log:

::set-output name=action_echo::enabled

Only the second set-output and echo workflow commands are included in the log because command echoing was only enabled when they were run. Even though it is not always echoed, the output parameter is set in all cases.

Sending values to the pre and post actions

You can use the save-state command to create environment variables for sharing with your workflow's pre: or post: actions. For example, you can create a file with the pre: action, pass the file location to the main: action, and then use the post: action to delete the file. Alternatively, you could create a file with the main: action, pass the file location to the post: action, and also use the post: action to delete the file.

If you have multiple pre: or post: actions, you can only access the saved value in the action where save-state was used. For more information on the post: action, see "Metadata syntax for GitHub Actions."

The save-state command can only be run within an action, and is not available to YAML files. The saved value is stored as an environment value with the STATE_ prefix.

This example uses JavaScript to run the save-state command. The resulting environment variable is named STATE_processID with the value of 12345:

console.log('::save-state name=processID::12345')

The STATE_processID variable is then exclusively available to the cleanup script running under the main action. This example runs in main and uses JavaScript to display the value assigned to the STATE_processID environment variable:

console.log("The running PID from the main action is: " +  process.env.STATE_processID);

Environment files

During the execution of a workflow, the runner generates temporary files that can be used to perform certain actions. The path to these files are exposed via environment variables. You will need to use UTF-8 encoding when writing to these files to ensure proper processing of the commands. Multiple commands can be written to the same file, separated by newlines.

Warning: On Windows, legacy PowerShell (shell: powershell) does not use UTF-8 by default. Make sure you write files using the correct encoding. For example, you need to set UTF-8 encoding when you set the path:

    uses: windows-2019
      - shell: powershell
        run: echo "mypath" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

Or switch to PowerShell Core, which defaults to UTF-8:

    uses: windows-2019
      - shell: pwsh
        run: echo "mypath" | Out-File -FilePath $env:GITHUB_PATH -Append # no need for -Encoding utf8

More detail about UTF-8 and PowerShell Core found on this great Stack Overflow answer:

Optional reading: The cross-platform perspective: PowerShell Core:

PowerShell is now cross-platform, via its PowerShell Core edition, whose encoding - sensibly - defaults to BOM-less UTF-8, in line with Unix-like platforms.

Setting an environment variable

echo "{environment_variable_name}={value}" >> $GITHUB_ENV

You can make an environment variable available to any subsequent steps in a workflow job by defining or updating the environment variable and writing this to the GITHUB_ENV environment file. The step that creates or updates the environment variable does not have access to the new value, but all subsequent steps in a job will have access. The names of environment variables are case-sensitive, and you can include punctuation. For more information, see "Environment variables."


  - name: Set the value
    id: step_one
    run: |
      echo "action_state=yellow" >> $GITHUB_ENV
  - name: Use the value
    id: step_two
    run: |
      echo "${{ env.action_state }}" # This will output 'yellow'

Multiline strings

For multiline strings, you may use a delimiter with the following syntax.



In this example, we use EOF as a delimiter and set the JSON_RESPONSE environment variable to the value of the curl response.

  - name: Set the value
    id: step_one
    run: |
      curl >> $GITHUB_ENV
      echo 'EOF' >> $GITHUB_ENV

Adding a system path

echo "{path}" >> $GITHUB_PATH

Prepends a directory to the system PATH variable and automatically makes it available to all subsequent actions in the current job; the currently running action cannot access the updated path variable. To see the currently defined paths for your job, you can use echo "$PATH" in a step or an action.


This example demonstrates how to add the user $HOME/.local/bin directory to PATH:

echo "$HOME/.local/bin" >> $GITHUB_PATH