Skip to content

Env vars in Github Actions

UPDATE: I made some false conclusions that I correct at the very bottom of this post.

I often use GitHub actions to automate tests, builds, and deployments. Naturally, I often have to deal with configuration values that I don't want to hardcode.

While there exists the option to provide inputs and outputs for Workflows and Actions, it is often cumbersome to pass these values around, especially if that needs to be very often. I had the idea to export some of my input variables to environment variables, so I don't have to re-define them everywhere I go.

In this post, I'll describe a Github Actions workflow together with a custom action that demonstrate how env variables are propagated and where we can use them. What I want to find out is:

  • if and how the environment variables are propagated from a workflow to the inside of an action
  • how I have to access the environment variables inside the action
  • can I use environment variables as default values for action parameters?

The workflow

First, I'll describe the sample workflow.

Inside the workflow, there are two environment variables set. Both will be used inside the action later.

I will also use the action twice, once without any parameters set (to see if the default value can be defined via an env variable) and then by simply overriding it (which actually is a no-brainer that this WILL override any default value, but just to be sure).

on:
  push:

name: Test Workflow
env:
  MY_ENV_1: "my env 1 is set"
  INPUT_DEFAULT_ENV: "input default env is set"

jobs:
  test_job:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout...
        uses: actions/checkout@v4
      - name: run the test action without set parameters
        uses: ./.github/actions/test_action
      - name: run the test action with explicit parameters
        uses: ./.github/actions/test_action
        with:
          input_with_default_env: "overriding the default env"

The action

name: Env var inheritance test
author: Thomas Niebler
inputs:
  input_with_default_env:
    description: "an input variable that has an environment value as default value"
    required: false
    default: $INPUT_DEFAULT_ENV
runs:
  using: composite
  steps:
    - name: Look at the env
      run: |
        echo ${{ env.MY_ENV_1 }}
        echo $MY_ENV_1
        echo input default env: ${{ inputs.input_with_default_env }}
        echo input default env was: $INPUT_DEFAULT_ENV
      shell: bash

The results

step 1

my env 1 is set
my env 1 is set
input default env: input default env is set
input default env was: input default env is set

step 2

my env 1 is set
my env 1 is set
input default env: overriding the default env
input default env was: input default env is set

Conclusion

We can see that the env variables are propagated from the workflow to the action. They can naturally be accessed via ${{ env.VAR_NAME }} or $VAR_NAME.

However, more interesting for me is that I can set default values for action parameters using environment variables from outside the action. For example, I could set a default value for a parameter that is used in multiple actions or workflows, but each time depending on the workflow.

UPDATE: Some false conclusions and their corrections

A few days later, I found out that I drew some false conclusions from the outputs given above.

Concretely, the default value for the input_with_default_env parameter is not set via the environment variable. In fact, it sets the string $INPUT_DEFAULT_ENV as the default value, but does not replace it with the value of the environment variable. However, in the very simple experiment setup that I did, this value is being entered into a bash environment. In detail, the replacement steps work as follows:

  1. The Github action sees that it should run the text

bash echo input default env: ${{ inputs.input_with_default_env }}

in a bash shell. The important thing here is that GitHub actions indeed sees the bash command above as pure text. The only thing it cares about is to replace the ${{ inputs.input_with_default_env }} with the default value defined in the Action's header. This is the string $INPUT_DEFAULT_ENV. So the first step of the Action is to replace the placeholder with the default value, resulting in:

bash echo input default env: $INPUT_DEFAULT_ENV

  1. In the second step, this command with the replaced default value is being executed in a bash shell. Now, this is still a string for the Action, but the bash shell sees the $INPUT_DEFAULT_ENV and replaces it with the value of the environment variable, because it knows that this is an environment variable. This is why the output of the action is input default env: input default env is set.

So, in fact, it is not DIRECTLY possible to propagate environment variables into Actions like this. Still, we can use env variables not as default parameters, but via the ${{ env.VAR_NAME }} syntax.