GitHub Actions Tutorial — Environment Variables

2 minute read

Environment Variables

Environment variables in GitHub Actions work at three levels: workflow, job, and step. Variables defined at a lower level override those at a higher level.


Three Scopes


env:                          # ← workflow level (all jobs)
  APP_NAME: my-app

jobs:
  build:
    runs-on: ubuntu-latest
    env:                      # ← job level (this job only)
      NODE_ENV: production
    steps:
      - name: Build
        env:                  # ← step level (this step only)
          API_URL: https://api.example.com
        run: |
          echo "App: $APP_NAME"       # from workflow
          echo "Env: $NODE_ENV"       # from job
          echo "API: $API_URL"        # from step

Override Priority

Step > Job > Workflow. If the same variable name is defined at multiple levels, the most specific scope wins.


Default Environment Variables

GitHub automatically sets these variables in every workflow run:

Variable Example Value
GITHUB_REPOSITORY owner/repo-name
GITHUB_REF refs/heads/main
GITHUB_REF_NAME main
GITHUB_SHA abc123def456...
GITHUB_ACTOR octocat
GITHUB_EVENT_NAME push
GITHUB_WORKSPACE /home/runner/work/repo/repo
GITHUB_RUN_ID 1234567890
GITHUB_RUN_NUMBER 42
RUNNER_OS Linux
RUNNER_ARCH X64

Access Default Variables


steps:
  - run: |
      echo "Repository: $GITHUB_REPOSITORY"
      echo "Branch: $GITHUB_REF_NAME"
      echo "Commit: $GITHUB_SHA"
      echo "Run #$GITHUB_RUN_NUMBER"


Using Variables in Expressions

Access env vars in expressions with the env context:


env:
  DEPLOY_TARGET: production

jobs:
  deploy:
    runs-on: ubuntu-latest
    if: env.DEPLOY_TARGET == 'production'
    steps:
      - run: echo "Deploying to ${{ env.DEPLOY_TARGET }}"


Configuration Variables (vars)

For non-sensitive configuration, use repository variables (Settings → Secrets and variables → Actions → Variables tab):


steps:
  - run: |
      echo "App name: ${{ vars.APP_NAME }}"
      echo "API URL: ${{ vars.API_BASE_URL }}"

Feature env: (in YAML) vars.* (repo variables)
Defined in Workflow file GitHub Settings UI/API
Visible in code Yes No (referenced only)
Can be org-wide No Yes
Encrypted No No
For secrets ❌ Never ❌ Never

Dynamic Environment Variables

Set variables dynamically using $GITHUB_ENV:


steps:
  - name: Set dynamic vars
    run: |
      echo "BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV"
      echo "SHORT_SHA=${GITHUB_SHA::7}" >> "$GITHUB_ENV"

  - name: Use dynamic vars
    run: |
      echo "Built at: $BUILD_TIME"
      echo "Commit: $SHORT_SHA"


Common Mistakes

Mistake Fix
Using secrets in env: at workflow level Secrets can’t be used at workflow-level env:. Use job or step level.
Variable not available in if: Use ${{ env.VAR }} in expressions, not $VAR
Env var from one run: step not in next Use $GITHUB_ENV to persist across steps
Hardcoding config in YAML Use vars.* for repo/org-level configuration

Quick Reference

Scope Syntax Available To
Workflow env: at top level All jobs
Job env: under job All steps in job
Step env: under step That step only
Dynamic >> "$GITHUB_ENV" Subsequent steps
Repo variable ${{ vars.NAME }} All workflows
Default $GITHUB_* All steps

← Back to: Chapter 6: Environment & Secrets

Next: Secrets →

Updated: