GitHub Actions — Automate Everything
What GitHub Actions Is
GitHub Actions is an event-driven automation platform built directly into GitHub. It executes arbitrary code in response to events that happen in your repository: a push to a branch, a pull request being opened, an issue being labeled, a release being published, a schedule, or a manual trigger.
The practical effect is enormous: every aspect of your software delivery process can be automated. Tests run automatically on every PR. Code is deployed to production as soon as it merges. A release draft is created when a tag is pushed. Dependencies are kept up to date without manual intervention. Security scans run on every commit. Changelogs are generated. Notifications are sent. Documentation is built and published. All of this happens without human coordination, running on infrastructure GitHub provides for free (within limits) or on your own servers.
GitHub Actions is not unique — Jenkins, CircleCI, GitLab CI, and others solve similar problems. But Actions is tightly integrated with GitHub's event system, has a massive marketplace of pre-built automation components, and is the default choice for any project hosted on GitHub.
Core Concepts
Understanding Actions requires understanding its five core abstractions:
Workflows
A workflow is an automated process defined in a YAML file. Workflows live in .github/workflows/ in your repository. Every .yml or .yaml file in that directory is a workflow.
A workflow specifies:
- When it runs (the trigger/event)
- What it runs (jobs containing steps)
You can have multiple workflow files — common patterns: one for CI, one for deployment, one for automated releases, one for scheduled maintenance.
Jobs
A job is a set of steps that run on a single runner (a virtual machine). Jobs in the same workflow run in parallel by default. You can make jobs sequential using the needs keyword.
Each job starts with a fresh runner environment — there is no shared state between jobs unless you explicitly use artifacts to pass data.
Steps
A step is an individual task within a job. Steps run sequentially within a job, sharing the same runner's filesystem and environment variables.
A step is either:
- A shell command (
run: npm test) - An action (
uses: actions/checkout@v4)
Actions
An action is a reusable unit of automation packaged as a repository. Actions are the building blocks of workflows — instead of writing shell commands for common tasks, you use actions that someone else has already written and tested.
Actions can be:
- JavaScript actions — run directly on the runner
- Docker container actions — run in a Docker container
- Composite actions — combine other actions and shell commands
The GitHub Actions Marketplace at github.com/marketplace?type=actions hosts thousands of community-built actions.
Runners
A runner is the virtual machine that executes a job. GitHub provides hosted runners:
ubuntu-latest(Linux) — fastest and most commonly usedwindows-latest(Windows)macos-latest(macOS) — slower and consumes more usage minutes
GitHub also supports self-hosted runners — VMs or physical machines you control, registered to run jobs. Self-hosted runners are used when:
- You need access to private network resources
- You need specific hardware (GPUs, ARM processors)
- You want to avoid GitHub's per-minute charges at scale
Workflow File Anatomy
Every workflow file follows the same top-level structure:
Triggers
The on: key defines when the workflow runs. Most workflows use one or more of these triggers:
push
Runs when commits are pushed to the repository:
pull_request
Runs when PR-related events occur:
By default, pull_request triggers on opened, synchronize, and reopened — sufficient for most CI workflows.
schedule
Runs on a cron schedule:
Cron syntax: minute hour day-of-month month day-of-week
Scheduled workflows run on the default branch. Common uses: nightly security scans, weekly dependency checks, periodic cleanup tasks.
workflow_dispatch
Enables manual triggering from the GitHub UI or CLI:
With inputs, the GitHub UI shows a form when manually triggering the workflow. The values are accessed in the workflow as ${{ inputs.environment }}.
Trigger manually via CLI:
release
Runs when a release is published, created, or edited:
Common use: automatically build and upload release artifacts when a new version is published.
issue_comment
Runs when a comment is created on an issue or PR:
Used for ChatOps workflows: a comment like /deploy staging can trigger a deployment workflow.
Combining Multiple Triggers
Your First Workflow — Hello World
Create .github/workflows/hello.yml:
Push this file to your repository's main branch. In the Actions tab, you will see the workflow run. Click it to see the job. Click the job to see the individual steps and their output.
Default Environment Variables
GitHub Actions populates several environment variables automatically in every workflow run:
| Variable | Value |
|----------|-------|
| GITHUB_REPOSITORY | owner/repo |
| GITHUB_REF | refs/heads/main or refs/tags/v1.0.0 |
| GITHUB_REF_NAME | main or v1.0.0 (short form) |
| GITHUB_SHA | Full commit SHA that triggered the workflow |
| GITHUB_ACTOR | Username of the person who triggered the workflow |
| GITHUB_EVENT_NAME | push, pull_request, workflow_dispatch, etc. |
| GITHUB_WORKSPACE | Path to the checked-out code |
| RUNNER_OS | Linux, Windows, or macOS |
| GITHUB_TOKEN | Automatically-generated token for this workflow run |
Using Marketplace Actions
Rather than writing shell scripts for common tasks, use actions from the marketplace. Actions are referenced with the uses: keyword and always include a version reference.
actions/checkout
Every workflow that needs to access the repository's code must check it out. The actions/checkout action does this:
actions/setup-node
Sets up a specific Node.js version on the runner:
actions/setup-python
actions/cache
Caches directories between workflow runs to speed up builds:
The cache key includes a hash of package-lock.json. If the lockfile changes, the cache is invalidated and rebuilt. If it hasn't changed, the cached ~/.npm directory is restored, making npm ci much faster.
actions/upload-artifact and actions/download-artifact
Pass build outputs between jobs:
A Complete CI Workflow
Putting the concepts together, here is a production-ready CI workflow for a Node.js project:
This workflow:
- Runs
lintandtestin parallel - Only runs
buildif both pass - Uploads the coverage report as an artifact (viewable from the Actions tab)
- Uploads the build output as an artifact for potential use in a downstream deployment workflow
Viewing Workflow Runs and Logs
In the GitHub UI
- Click the Actions tab in your repository.
- The left sidebar lists all workflows. Click one to filter runs by workflow.
- Each row in the main area is a workflow run with:
- Status icon (queued, in progress, success, failure, cancelled)
- Workflow name and branch
- Commit message
- Actor (who triggered it)
- Duration
- Click a run to see all jobs.
- Click a job to see all steps.
- Click a step to expand its log output.
Searching Workflow Runs
Use the filters at the top of the Actions tab:
- Filter by Status: Success, Failure, Cancelled, In Progress
- Filter by Branch
- Filter by Actor
- Filter by Event: push, pull_request, schedule, etc.
Via gh CLI
Re-Running Failed Jobs
Not every failure requires code changes — sometimes a test is flaky, a network request times out, or a dependency download fails intermittently. GitHub Actions supports re-running failed jobs without re-running the entire workflow.
Via UI
On a failed workflow run page, click Re-run failed jobs (partial re-run, starting from the first failed job) or Re-run all jobs (full re-run).
Via gh CLI
Debug logging is extremely useful for diagnosing failures — it shows every shell command executed and every variable expanded.
Workflow Syntax Reference
Key syntax elements you will use frequently:
Setting Environment Variables
Expressions and Contexts
Available contexts: github, env, jobs, steps, runner, secrets, inputs
Outputs Between Steps
Timeouts
Practical Exercises
Exercise 1 — Hello World Workflow
- Create
.github/workflows/hello.ymlin a repository. - Add a trigger for
pushtomainandworkflow_dispatch. - Add a job with 3 steps: one that echoes a greeting, one that prints environment variables, and one that runs a multi-line script.
- Push to
mainand view the run in the Actions tab. - Manually trigger the workflow from the Actions tab UI.
Exercise 2 — CI Workflow with Caching
- In a repository with a
package.jsonand a test script, create a CI workflow. - Add dependency caching using
actions/cacheor thecacheparameter inactions/setup-node. - Run the workflow twice. Check the second run's logs — the "Cache hit" message should appear and the install step should be significantly faster.
Exercise 3 — Multi-Job Workflow
- Create a workflow with three jobs:
lint,test, andbuild. - Make
builddepend on bothlintandtestusingneeds. - Deliberately make the
lintjob fail and observe thatbuilddoes not run. - Fix the lint failure and observe all three jobs run successfully.
Exercise 4 — workflow_dispatch with Inputs
- Create a workflow with a
workflow_dispatchtrigger. - Add two inputs: a string
messageand a booleanverbose. - In the workflow, echo the message. If
verboseis true, also echo additional details. - Trigger the workflow manually from the Actions tab with different input values.
Exercise 5 — Artifact Upload
- Create a workflow that generates some output file (e.g.,
echo "report" > report.txt). - Upload the file as an artifact using
actions/upload-artifact. - View the artifact in the workflow run summary and download it.