GitHub Actions
GitHub Actions Core Concepts
Working with Variables at different levels
Streamline your GitHub Actions workflows by reducing duplication and centralizing configuration with environment variables. In this guide, you’ll learn to declare variables at the step, job, and workflow levels, so you can:
- Maintain clean, DRY workflows
- Easily update container names, registry endpoints, and other parameters
- Secure sensitive data using GitHub Secrets
Below is a sample workflow file (variable-secrets.yaml
) that builds, pushes, and deploys a Docker image:
name: Exploring Variables and Secrets
on:
push:
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Docker Build
run: docker build -t docker.io/dockerUsername/imageName:latest
- name: Docker Login
run: docker login --username=dockerUsername --password=s3CuRePa$$w0rd
- name: Docker Publish
run: docker push docker.io/dockerUsername/imageName:latest
deploy:
needs: docker
runs-on: ubuntu-latest
steps:
- name: Docker Run
run: docker run -d -p 8080:80 docker.io/dockerUsername/imageName:latest
Whenever you push:
- GitHub Actions builds the Docker image.
- Logs in to Docker Hub.
- Pushes the image.
- Runs the container in the
deploy
job, which depends ondocker
.
Notice how the registry, username, and image name are repeated. Let’s eliminate this duplication using environment variables.
Overview of Environment Variable Scopes
Level | Declaration Location | Scope |
---|---|---|
Step-level | Inside a specific step | Only that step |
Job-level | Under jobs.<job_id>.env | All steps within that job |
Workflow-level | Top of the YAML file | Every job and step in the workflow |
1. Step-Level Environment Variables
Define variables in an individual step. This is ideal for values that aren’t reused elsewhere.
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Docker Build
env:
CONTAINER_REGISTRY: docker.io
DOCKER_USERNAME: siddharth1
IMAGE_NAME: github-actions-nginx
run: |
docker build -t $CONTAINER_REGISTRY/$DOCKER_USERNAME/$IMAGE_NAME:latest
- name: Docker Login
env:
DOCKER_USERNAME: siddharth1
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: |
docker login --username=${DOCKER_USERNAME} \
--password=${DOCKER_PASSWORD}
- name: Docker Publish
env:
CONTAINER_REGISTRY: docker.io
DOCKER_USERNAME: siddharth1
IMAGE_NAME: github-actions-nginx
run: |
docker push $CONTAINER_REGISTRY/$DOCKER_USERNAME/$IMAGE_NAME:latest
deploy:
needs: docker
runs-on: ubuntu-latest
steps:
- name: Docker Run
env:
CONTAINER_REGISTRY: docker.io
DOCKER_USERNAME: siddharth1
IMAGE_NAME: github-actions-nginx
run: |
docker run -d -p 8080:80 \
${{ env.CONTAINER_REGISTRY }}/${{ env.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:latest
You can reference an environment variable using:
$VAR_NAME
${{ env.VAR_NAME }}
(recommended when mixing with expressions)
2. Job-Level Environment Variables
Apply the same variables to all steps in a job by declaring them under jobs.<job_id>.env
:
jobs:
docker:
runs-on: ubuntu-latest
env:
CONTAINER_REGISTRY: docker.io
DOCKER_USERNAME: siddharth1
IMAGE_NAME: github-actions-nginx
steps:
- name: Docker Build
run: |
docker build -t $CONTAINER_REGISTRY/$DOCKER_USERNAME/$IMAGE_NAME:latest
- name: Docker Login
env:
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: |
docker login --username=${DOCKER_USERNAME} \
--password=${DOCKER_PASSWORD}
- name: Docker Publish
run: |
docker push $CONTAINER_REGISTRY/$DOCKER_USERNAME/$IMAGE_NAME:latest
deploy:
needs: docker
runs-on: ubuntu-latest
env:
CONTAINER_REGISTRY: docker.io
DOCKER_USERNAME: siddharth1
IMAGE_NAME: github-actions-nginx
steps:
- name: Docker Run
run: |
docker run -d -p 8080:80 \
$CONTAINER_REGISTRY/$DOCKER_USERNAME/$IMAGE_NAME:latest
Any env
under a job cascades to every step. You can still override or augment variables at the step level.
3. Workflow-Level Environment Variables
Declare variables at the top of your workflow to make them available across all jobs and steps:
name: Exploring Variables and Secrets
on:
push:
env:
CONTAINER_REGISTRY: docker.io
DOCKER_USERNAME: siddharth1
IMAGE_NAME: github-actions-nginx
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Docker Build
run: |
docker build -t ${{ env.CONTAINER_REGISTRY }}/${{ env.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:latest
- name: Docker Login
env:
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: |
docker login --username=${DOCKER_USERNAME} \
--password=${DOCKER_PASSWORD}
- name: Docker Publish
run: |
docker push $CONTAINER_REGISTRY/$DOCKER_USERNAME/$IMAGE_NAME:latest
deploy:
needs: docker
runs-on: ubuntu-latest
steps:
- name: Docker Run
run: |
docker run -d -p 8080:80 \
$CONTAINER_REGISTRY/$DOCKER_USERNAME/$IMAGE_NAME:latest
Warning
Never hard-code sensitive values like passwords or API keys. Store them in GitHub Secrets and reference them with ${{ secrets.YOUR_SECRET_NAME }}
.
Verifying Your Workflow
- Commit and push your changes.
- Open the Actions tab in your repository.
- Watch the docker and deploy jobs run sequentially.
- Expand each step to confirm that variables are correctly substituted and that secrets remain masked.
Note
Use ${{ env.VAR_NAME }}
when combining expressions with literal strings to ensure consistent parsing.
References
Watch Video
Watch video content