GitHub Actions Tutorial — Environment Variables
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 →