GitHub Actions Environment Variables

Environment variables are named values that your workflow steps can read at runtime. They let you pass information to commands without hardcoding values directly in scripts. GitHub provides many built-in variables automatically, and you can define your own at different scopes within a workflow.

What an Environment Variable Is

Think of an environment variable as a labeled sticky note placed on the runner's desk. Any step that runs on that machine can read the note. The step does not need to know in advance what the value is — it just asks for the note by name.

Sticky note on runner:
  APP_NAME = "my-web-app"

Step reads the note:
  echo "Building $APP_NAME"

Output:
  Building my-web-app

GitHub's Built-In Environment Variables

GitHub automatically sets dozens of variables before your workflow starts. You can use them in any step without defining them yourself.

Variable              | What it contains
----------------------|----------------------------------------------
GITHUB_REPOSITORY     | owner/repo-name (e.g. "acme/my-app")
GITHUB_SHA            | The full commit hash that triggered the run
GITHUB_REF            | The branch or tag ref (e.g. "refs/heads/main")
GITHUB_ACTOR          | GitHub username of who triggered the workflow
GITHUB_WORKFLOW       | Name of the current workflow
GITHUB_RUN_NUMBER     | A number that increments with each run
GITHUB_EVENT_NAME     | The event that started the workflow (e.g. "push")
GITHUB_WORKSPACE      | The directory where your code is checked out
RUNNER_OS             | Operating system of the runner (Linux/Windows/macOS)

Access them in shell commands using the $VARIABLE_NAME syntax on Linux and macOS, or $env:VARIABLE_NAME on Windows:

steps:
  - name: Show commit info
    run: |
      echo "This run was triggered by: $GITHUB_ACTOR"
      echo "Running on commit: $GITHUB_SHA"
      echo "Repository: $GITHUB_REPOSITORY"

Defining Your Own Environment Variables

You can define custom environment variables at three different levels: workflow level, job level, and step level. Each level has a different scope — how widely the variable is visible.

Workflow-Level Variables

Variables defined at the top level are available to every job and step in the workflow:

name: Build Pipeline

env:
  NODE_ENV: production
  APP_VERSION: 3.2.1

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building version $APP_VERSION for $NODE_ENV"

Job-Level Variables

Variables defined inside a job are available only to steps within that job:

jobs:
  test:
    runs-on: ubuntu-latest
    env:
      TEST_TIMEOUT: 30000
    steps:
      - run: echo "Timeout is $TEST_TIMEOUT ms"

Step-Level Variables

Variables defined inside a step are available only for the duration of that single step:

steps:
  - name: Run with custom variable
    env:
      LOG_LEVEL: debug
    run: echo "Log level is $LOG_LEVEL"

Variable Scope Diagram

Workflow env block
├── Job 1 env block (overrides workflow-level if same name)
│   ├── Step A env block (overrides job-level if same name)
│   └── Step B env block
└── Job 2 env block
    └── Step C env block

A variable defined closer to the step always wins over one defined further away. A step-level variable named APP_ENV overrides a job-level or workflow-level variable with the same name.

Setting Variables Dynamically at Runtime

A step can write a variable to a special file called $GITHUB_ENV, making it available to all subsequent steps in the same job:

steps:
  - name: Compute build number
    run: echo "BUILD_NUMBER=42" >> $GITHUB_ENV

  - name: Use the build number
    run: echo "Building number $BUILD_NUMBER"

The first step writes a new variable into the environment. The second step reads it as if it were always there. This technique is useful when a value cannot be known until a step runs — like a version number generated by a script.

Expressions in Environment Variables

You can use GitHub's expression syntax inside variable values:

env:
  BRANCH_NAME: ${{ github.ref_name }}
  IS_MAIN: ${{ github.ref_name == 'main' }}

The ${{ }} syntax evaluates the expression and inserts the result. github.ref_name returns just the branch name (like main) rather than the full ref path.

Environment Variables vs Secrets

Environment variables are visible in plain text in your workflow logs. Never store passwords, API keys, or tokens in environment variables directly. Use GitHub Secrets instead (covered in the next topic) for any sensitive data.

Safe to put in env:         Use Secrets for:
─────────────────────────   ─────────────────────────
APP_NAME = "my-app"         DATABASE_PASSWORD
NODE_ENV = "production"     AWS_ACCESS_KEY_ID
LOG_LEVEL = "info"          DEPLOY_TOKEN
BUILD_VERSION = "2.1"       SLACK_WEBHOOK_URL

Viewing Environment Variables in Logs

Run the following command in a step to print all environment variables available on the runner. This is useful when debugging a workflow that behaves unexpectedly:

steps:
  - name: Debug environment
    run: env | sort

This prints every variable alphabetically. Remove this step before finalizing your workflow — it may expose sensitive system paths or values you do not want visible in logs.

Leave a Comment

Your email address will not be published. Required fields are marked *