GitHub Actions
GitHub Actions
Definition: GitHub’s built-in CI/CD platform, running automated workflows directly inside a GitHub repository in response to events like pushes, pull requests, or issue comments. Announced in October 2018 and reaching general availability in November 2019, it arrived years after both GitLab CI/CD and Jenkins but leveraged GitHub’s massive existing developer base to become the default CI choice for most new GitHub-hosted projects almost immediately. Workflows are defined as YAML files committed alongside the code they build, so the pipeline definition lives in the same repository, branch, and pull-request review process as everything else, rather than in a separate system.
Core Services & Concepts
- Workflows — CI/CD pipeline definitions written as YAML files in
.github/workflows/, triggered by repository events likepush,pull_request,schedule, or a manualworkflow_dispatch - Jobs and steps — a workflow contains one or more jobs, each running on a runner and executing a sequence of steps; jobs run in parallel by default unless a
needsdependency links them - Runners — the machines that execute workflow jobs, either GitHub-hosted (Ubuntu, Windows, or macOS VMs provisioned fresh per job) or self-hosted (persistent machines an operator registers)
- Actions — reusable, packaged units of workflow logic (JavaScript, Docker-container, or composite actions), published individually or shared through the GitHub Marketplace
- Secrets and environments — encrypted repository or organization-level secrets injected into workflows at runtime, with environments adding required-reviewer approval gates before a deployment job proceeds
GITHUB_TOKEN— an automatically generated, scoped token injected into every workflow run so steps can authenticate back to the GitHub API without manually managing credentials- Matrix builds — a single job definition expanded across a matrix of variables (OS, language version, etc.), spawning many parallel job instances from one YAML block
- Reusable workflows and composite actions — mechanisms for sharing pipeline logic across repositories, avoiding copy-pasted YAML for common build-test-deploy patterns
- Artifacts and caching —
actions/upload-artifactpersists build outputs between jobs or for later download, whileactions/cachespeeds up repeat runs by persisting dependency directories
How It Works: Event-Driven Workflow Execution
- Every workflow declares an
on:trigger — a repo event, a cron schedule, or a manualworkflow_dispatch— and GitHub watches for matching events to queue a run - On trigger, GitHub provisions a fresh, ephemeral virtual machine per job for GitHub-hosted runners; nothing is checked out automatically, so the workflow’s first step is almost always
actions/checkout - Jobs within a workflow run in parallel across separate runners by default; the
needs:key builds an explicit dependency graph so a deploy job can wait for a test job to succeed first - Steps within a single job run sequentially on the same runner and share filesystem state, letting one step build an artifact that the next step consumes directly
- Self-hosted runners register with a repository or organization via a long-lived agent process, useful for specialized hardware, private network access, or avoiding per-minute billing on heavy workloads
- Concurrency groups (
concurrency:) let a workflow automatically cancel or queue superseded runs — for example, canceling an in-progress deploy when a newer commit lands on the same branch
How Pricing Works
- Public repositories get unlimited free Actions minutes on GitHub-hosted runners, a major reason for its default status among open-source projects
- Private repositories get a monthly free-minutes allowance tied to the account’s plan (Free, Team, Enterprise), with additional minutes billed per-minute beyond that
- Minutes carry an OS multiplier — Linux runs at roughly 1x, Windows around 2x, macOS historically around 10x — so identical workloads cost far more on macOS runners
- Self-hosted runners avoid GitHub’s per-minute billing entirely since the compute is the operator’s own infrastructure, though job concurrency limits still vary by plan
- Storage for artifacts and GitHub Packages beyond the included allotment is billed separately, and unused artifacts quietly accumulate cost until their retention period expires
Pros
- Zero setup for any project already hosted on GitHub — no separate CI system, account, or integration to configure
- Enormous Marketplace of prebuilt, community-maintained actions covering nearly any common CI/CD task
- Tight native integration with pull requests, checks, and issues — workflow status shows directly in the PR review UI
- Generous free tier for public repositories makes it the default choice for most open-source projects
- GitHub-hosted runners require no infrastructure management, spinning up fresh for every single job
- Matrix builds and reusable workflows make cross-platform testing and DRY pipeline logic straightforward to express
Cons
- Tied tightly to GitHub — migrating to another platform means rewriting the entire CI configuration from scratch
- Self-hosted runners require the same ongoing infrastructure management as any other self-managed compute fleet
- macOS runner minutes are billed at a steep multiplier, making cross-platform Apple CI expensive at real scale
- Debugging a failing workflow often means pushing commits and waiting, since local emulation (
act) has real fidelity gaps - Self-hosted runners on public repositories are a known security risk, since a malicious fork’s PR can potentially execute code on them
- Complex pipelines built from many reusable workflows and composite actions can become as hard to trace as any sprawling YAML system
Comparison: GitHub Actions vs GitLab CI/CD vs Jenkins
| GitHub Actions | GitLab CI/CD | Jenkins | |
|---|---|---|---|
| Hosting model | SaaS (GitHub-hosted) or self-hosted runners | SaaS (GitLab.com) or self-hosted | Self-hosted only, no official SaaS offering |
| Config format | YAML workflows in .github/workflows/ | YAML in a single .gitlab-ci.yml | Groovy-based Jenkinsfile, or legacy UI jobs |
| Setup effort | Minimal if the project already lives on GitHub | Minimal if the project already lives on GitLab | Significant — install, configure, and maintain a server |
| Extensibility | Marketplace Actions built by the community | Built-in features plus shareable templates/includes | Massive plugin ecosystem, roughly 1,800+ plugins |
| Maintenance burden | Low, GitHub manages hosted runners | Low to medium, higher if self-hosted | High — the team owns the entire server and agent fleet |
| Pricing model | Free public repos, per-minute billing for private | Free tier plus tiered compute-minute billing | Free and open-source, cost is entirely infra and ops time |
| Best fit | Projects already hosted on GitHub | Teams wanting one all-in-one DevOps platform | Teams needing maximum customization and full control |
Best For
- Any project already hosted on GitHub wanting CI/CD without adopting or paying for a separate platform
- Open-source projects that want free, unlimited CI on public repositories plus a large marketplace of ready-made actions
- Teams that want CI/CD status tightly woven into the pull request review workflow itself
Real Examples
- Microsoft’s own open-source repositories, including VS Code and TypeScript, build and test using GitHub Actions
- Homebrew’s package formulae are tested and published through GitHub Actions workflows
- Countless npm and PyPI packages ship releases via GitHub Actions workflows triggered on tag pushes
Use Cases
- Running a project’s test suite automatically on every pull request before merge is allowed
- Automated deployment to staging or production on merge to main, gated by environment approval rules
- Scheduled jobs — nightly builds, dependency vulnerability checks, stale-issue cleanup — run on cron triggers
- Building and pushing container images to a registry on every tagged release
- Automating linting, formatting checks, and code-quality gates as required PR status checks
- Release automation — generating changelogs, tagging versions, and publishing packages when a release is cut
Integration Notes & Common Pitfalls
- Pin third-party actions to a specific commit SHA rather than a mutable tag like
@main, since an unpinned action can change behavior — or turn malicious — without warning - Fork pull requests don’t receive repository secrets by default, a deliberate security boundary that trips up maintainers expecting secrets to “just work” on community PRs
- Scope
GITHUB_TOKENpermissions explicitly per workflow with apermissions:block rather than relying on the broad default, following least-privilege practice - Artifact and log retention has a default expiry, commonly 90 days, so workflows relying on artifacts long-term need an external storage step
- Concurrency limits vary sharply by plan tier, and a Free-tier org can see jobs queue unexpectedly during busy periods compared to Enterprise
- Self-hosted runners registered at the repository level on a public repo are a real attack surface — scope them to private repos or use ephemeral, isolated runners
Code Example
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm ci
- run: npm test
Code Example: Matrix Build Across Node Versions
jobs:
test:
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
Ecosystem
- GitHub Marketplace — the public catalog of community and verified actions covering deployment, security scanning, notifications, and nearly every common CI task
act— a third-party tool that emulates GitHub Actions locally in Docker, useful for faster iteration though not a perfect match for hosted runner behavior- Dependabot — GitHub’s native dependency-update bot, commonly paired with Actions workflows to auto-test and merge version bumps
- CodeQL — GitHub’s semantic code analysis engine, runs as an Actions workflow to scan for security vulnerabilities on every push
actions/checkout,actions/cache,docker/build-push-action— a small set of official and widely trusted community actions that appear in the overwhelming majority of real-world workflows
Best Practices
- Pin every third-party action to a commit SHA, not a floating version tag, and review diffs when bumping pinned versions
- Use environments with required reviewers for any workflow that deploys to production, turning deployment into an explicit, auditable gate
- Scope
GITHUB_TOKENand secret access to the minimum each job actually needs, rather than granting broad default permissions - Cache dependencies with
actions/cachefor any workflow with a meaningful install step, since the time savings compound quickly across frequent runs - Extract shared logic into reusable workflows or composite actions instead of duplicating the same YAML across repositories
- Use concurrency groups to automatically cancel stale, superseded runs on the same branch or PR, saving both time and minutes
FAQ
Is GitHub Actions free? Yes for public repositories, with unlimited minutes on GitHub-hosted runners; private repositories get a monthly free allowance and are billed per minute beyond it.
Can GitHub Actions deploy to AWS, GCP, or Azure? Yes — the Marketplace has official and community actions for every major cloud provider, and many teams pair Actions with Terraform or cloud CLI tools inside a workflow step to handle the actual deployment.
How is GitHub Actions different from Jenkins? GitHub Actions is a hosted SaaS product tightly integrated with GitHub’s repository events and pull requests, while Jenkins is self-hosted, requires its own server and agent infrastructure, and is agnostic about where the source code lives.
Can I run GitHub Actions workflows locally before pushing?
Only approximately — the third-party act tool emulates workflow execution in Docker, but it doesn’t perfectly replicate GitHub-hosted runner environments, so some behavior still needs a real push to verify.
What happens if a workflow’s action gets compromised? Any action referenced by a mutable tag or branch could start running malicious code on the very next workflow run, which is exactly why pinning to a commit SHA is treated as a security best practice rather than a nice-to-have.
Common Interview Questions
- “How do you structure a GitHub Actions workflow to avoid duplicating logic across multiple pipelines?” — expect a discussion of reusable workflows and composite actions
- “What security risks come with self-hosted runners, and how do you mitigate them?” — expect fork-PR isolation, ephemeral runners, and scoping runners away from public repositories
- “How would you speed up a slow CI pipeline in GitHub Actions?” — expect caching dependencies, parallelizing jobs, and using a matrix strategy instead of sequential loops
- “What’s the difference between an artifact and a cache in GitHub Actions?” — expect a distinction between artifacts as durable build outputs meant for download and caches as ephemeral performance optimizations for repeat runs
History
- GitHub itself was founded in 2008; Microsoft acquired GitHub in 2018 for roughly $7.5 billion, shortly before Actions was announced
- GitHub Actions was announced in October 2018 as a general workflow automation platform, initially with a broader scope than just CI/CD
- Reached general availability in November 2019, refocused specifically around CI/CD-style workflows triggered by repository events
- Reusable workflows and composite actions arrived in 2021, addressing early complaints about duplicated YAML across repositories
- Grew rapidly through the early 2020s to become the default CI choice for most new GitHub-hosted projects, aided by its zero-setup integration
- Continues to expand with features like larger hosted runners, immutable actions, and deeper artifact/attestation support for supply-chain security
Related Terms
Referenced by