Skip to content
Optimal Lab

Tools · interactive

GitHub Actions on every push

One YAML file decides what runs when you push. Follow an event through on:, parallel jobs, a matrix and needs:, and see why deploy only runs on main.

You

git push

GitHub

pull_request

ci.yml

on: matched

Runners

4 VMs

PR checks

passing

.github/workflows/ci.ymlname: CIon:  push:    branches: [main]  pull_request: jobs:  lint:    runs-on: ubuntu-latest    steps: [checkout, setup-node, npm ci, npm run lint]   test:    runs-on: ubuntu-latest    strategy:      matrix:        node: [18, 20, 22]    steps: [checkout, setup-node, npm ci, npm test]   deploy:    needs: [lint, test]    if: github.ref == 'refs/heads/main'    runs-on: ubuntu-latest    steps: [checkout, deploy]

Pick an event and run it. This one takes about 91s and 7 billable runner minutes.

Event

Step 1 of 5

  1. 1

    A push fires an event

    Every push, pull request, tag or schedule is an event with a name and a branch.

    pull_request on feature/login

  2. 2

    GitHub matches workflows by on:

    Each file in .github/workflows/ declares which events start it. No match, no run.

    ci.yml matches.

  3. 3

    Jobs start in parallel on fresh runners

    Jobs with no needs: start together, each on a clean VM. A matrix copies one job per value.

    • lint
    • test (node 18)
    • test (node 20)
    • test (node 22)

    npm ci downloads everything: 38s

  4. 4

    needs: waits, and if: can skip

    deploy waits for lint and every test. If any failed, or this isn't main, it's skipped and never takes a runner.

    deploy: skipped, if: this run is not on main.

  5. 5

    Results come back as checks

    Each job reports a check on the commit. Branch protection can require them before a merge.

    • lintsuccess
    • test (node 18)success
    • test (node 20)success
    • test (node 22)success
    • deployskipped

    Wall time ~91s · 7 billable minutes (each job rounds up)