GitHub Actions Workflow Basics
GitHub Actions is GitHub's native CI/CD platform, configured entirely through YAML files stored in the .github/workflows directory of a repository. Each YAML file defines a 'workflow' — an automated process made up of one or more 'jobs', which in turn are made up of ordered 'steps'. Because workflows live in the same repository as the code they build and test, they are versioned alongside it: a workflow change is reviewed in a pull request just like any other code change, and different branches can even run different pipeline logic.
Cricket analogy: A team's official playing strategy document lives in the same team folder as the player contracts, so when the strategy changes, it goes through the same selection-committee review as any roster change, and the domestic squad can run a different game plan than the national team.
The Structure of a Workflow File
Every workflow file has three essential top-level keys: 'name' (a human-readable label shown in the Actions tab), 'on' (the trigger — which events cause this workflow to run, covered in depth in the triggers topic), and 'jobs' (a map of job IDs to job definitions). Each job specifies 'runs-on' to select the runner environment (e.g. ubuntu-latest, windows-latest, macos-latest, or a self-hosted label) and a list of 'steps' that execute in order within that job.
Cricket analogy: Every match scorecard needs three essentials filled in before play starts: the match name, the format that triggers specific rules (T20, ODI, Test), and the squad list assigned to specific roles, just as every workflow needs 'name', 'on', and 'jobs'.
Steps: Actions vs. Shell Commands
A step is either a reusable 'action' (referenced via 'uses:', such as actions/checkout@v4) or an inline shell command (via 'run:'). Actions are the reusable building blocks of the GitHub Actions ecosystem — pinned to a version tag or commit SHA for reproducibility — while 'run' steps execute arbitrary shell commands directly on the runner. A well-structured workflow typically starts with actions/checkout to pull the repository code, since runners start with an empty filesystem.
Cricket analogy: A fielding drill either calls in a specialist reusable fielding coach pinned to that exact session, or the captain just runs it himself on the spot, and every practice sensibly starts by first laying out the boundary markers since the ground starts empty.
name: Build, Test, and Lint
on:
pull_request:
branches: [main]
jobs:
build-test-lint:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run flake8 linter
run: flake8 src/
- name: Run pytest
run: pytest --maxfail=1 --disable-warningsPassing Data With Environment Variables and Outputs
Steps within the same job share a filesystem and can pass data via environment variables set with the GITHUB_ENV file, or via explicit step 'outputs' declared with the GITHUB_OUTPUT file, which later steps or even later jobs (via 'needs' and 'jobs.<job_id>.outputs') can reference. Secrets like API tokens are injected via the 'secrets' context (e.g. ${{ secrets.DEPLOY_TOKEN }}) and are automatically masked in logs.
Cricket analogy: Players on the same team share the same dressing room and can pass a strategy note from one batsman to the next via the team's whiteboard, and a coded signal for a specific tactic is visible only to those who know the code, invisible to everyone else in the stands.
Pinning an action to a full commit SHA instead of a mutable tag like @v4 is the GitHub-recommended supply-chain security practice, since tags can be moved by the action's maintainer (or an attacker who compromises their account) to point at different code without changing the version number you see in your workflow file.
A common beginner mistake is forgetting actions/checkout as the first step. Runners start with a completely empty workspace, so without checking out the repository, subsequent steps referencing source files (npm ci, pytest, etc.) will fail because there is nothing there yet.
- Workflows are YAML files in .github/workflows, made of jobs, which are made of ordered steps.
- The top-level 'on' key defines what triggers the workflow to run.
- 'runs-on' selects the runner OS/environment for a job; jobs run on isolated, fresh virtual machines by default.
- Steps are either reusable 'uses:' actions or inline 'run:' shell commands.
- actions/checkout should almost always be the first step, since runners start with an empty filesystem.
- Pinning actions to a commit SHA (not just a version tag) improves supply-chain security.
Practice what you learned
1. Where must GitHub Actions workflow files be located in a repository?
2. What is the purpose of the top-level 'on' key in a workflow file?
3. Why do most jobs include 'actions/checkout' as their first step?
4. What is the security benefit of pinning an action to a full commit SHA instead of a version tag like @v4?
5. How are secrets like API tokens typically referenced inside a GitHub Actions step?
Was this page helpful?
You May Also Like
Jobs, Steps, and Runners
Jobs are independent units of work that run on isolated runners, steps are the ordered commands within a job, and runners are the actual machines that execute them.
GitHub Actions Triggers and Events
Learn how GitHub Actions workflows start: the `on:` key, common webhook events, scheduled runs, manual dispatch, and how to filter events by branch, path, or type.
Reusable Workflows and Composite Actions
Compare GitHub Actions' two mechanisms for eliminating duplicated pipeline logic — reusable workflows called with `uses:` at the job level, and composite actions bundling multiple steps.
The CI/CD Tooling Landscape
A survey of the major CI/CD platforms — GitHub Actions, GitLab CI, Jenkins, CircleCI, and Azure Pipelines — and how their hosting model, configuration approach, and ecosystem differ.
Related Reading
Related Study Notes in DevOps
Browse all study notesNginx Study Notes
DevOps · 30 topics
DevOpsAnsible Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics