At some point a repository stops having a workflow and starts having a CI/CD system — several repositories sharing standards, pipelines that must not be copy-pasted, runners chosen for hardware rather than convenience, and deployments that require someone’s approval.
That transition is what this cluster is about.
Start with Matrix BuildsThe problem each lesson solves
Section titled “The problem each lesson solves”Rather than a feature list, the honest framing is the problem that makes each feature necessary.
| Problem | Lesson |
|---|---|
| “We need to test across five versions and three platforms” | Matrix Builds |
| “Thirty repositories have the same 80-line workflow” | Reusable Workflows |
| “These six steps repeat in every job” | Composite Actions |
| “We need something no existing action does” | Custom Actions |
| “Our build needs hardware or network access GitHub cannot give us” | Self-Hosted Runners |
| “Model training needs a GPU” | GPU Runners |
| “We ship ARM64 and only test x64” | ARM Runners |
| “Every run spends four minutes downloading dependencies” | Caching |
| “The build output disappears when the job ends” | Artifacts |
| “Staging and production need different configuration” | Environments |
| “Production deployments need a human decision” | Deployment Approvals |
If none of those describe a problem you have, this cluster is premature. Adding reusable workflows to one repository, or a self-hosted runner to a project that builds fine on hosted ones, is complexity without a corresponding benefit.
Reuse: the central idea
Section titled “Reuse: the central idea”Three lessons cover reuse, and choosing between them is the most common question in this cluster.
Three application repositories each call one shared reusable CI workflow, which contains build, test and scan jobs. Below, an application workflow calls a reusable deployment workflow, which uses OIDC to authenticate to a cloud provider.
That upper shape is platform engineering in one picture: standards defined once, consumed by many, versioned like code. The lower shape is the same idea applied to deployment, where the reusable workflow also owns the cloud trust relationship — so individual application repositories never handle credentials at all.
Reusable workflow or composite action?
Section titled “Reusable workflow or composite action?”The distinction that causes the most confusion, stated once here and covered fully in both lessons.
| Reusable workflow | Composite action | |
|---|---|---|
| Called from | A job (uses: at job level) | A step (uses: inside steps:) |
| Can define multiple jobs | Yes | No |
| Chooses its own runner | Yes — each job has runs-on | No — runs inside the caller’s job |
| Defined in | A workflow YAML file | action.yml plus its implementation |
| Location | .github/workflows/ | Any directory, or its own repository |
| Secrets | Passed explicitly or inherited | Passed as inputs |
| Typical use | A complete CI or deployment pipeline | A repeated sequence of steps |
The one-line test: if it needs its own runner, it is a workflow. If it is a sequence of steps inside someone else’s job, it is a composite action.
Prerequisites
Section titled “Prerequisites”| You should be able to | Covered in |
|---|---|
| Write and debug a workflow | Fundamentals |
| Build a CI pipeline for a real project | Continuous Integration |
| Pass values between jobs | Outputs |
Reason about permissions | Least-Privilege Permissions |
The self-hosted runner lessons additionally assume you can provision and secure a machine. If that is not you, they are still worth reading — knowing what self-hosting costs is how you decide not to do it.
The learning path
Section titled “The learning path”- Lesson 1: 01. Matrix BuildsRun one job across many configurations — matrix axes, include and exclude, fail-fast, max-parallel, dynamic matrices from JSON, and keeping required checks stable.
- Lesson 2: 02. Reusable WorkflowsCall one workflow from another — workflow_call inputs, secrets and outputs, versioning, nesting limits, and how reusable workflows differ from composite actions.
- Lesson 3: 03. Composite ActionsPackage a sequence of steps as a reusable action — action.yml structure, inputs and outputs, the shell requirement, local versus published, and the limits to know.
- Lesson 4: 04. Custom ActionsWrite your own action — JavaScript, Docker container and composite types compared, action.yml metadata, the toolkit, bundling, testing, versioning and publishing.
- Lesson 5: 05. Self-Hosted RunnersRun workflows on your own machines — when self-hosting is justified, installing a runner, labels, runner groups, ephemeral runners and autoscaling with the Actions Runner Controller.
- Lesson 6: 06. GPU RunnersRun accelerated workloads in CI — GitHub-hosted GPU runner availability, self-hosted GPU fleets, verifying the device, container access and controlling the cost.
- Lesson 7: 07. ARM RunnersBuild natively on ARM with GitHub Actions — available Linux and Windows ARM runner labels, native versus emulated builds, and multi-architecture container images.
- Lesson 8: 08. CachingMake workflows fast with actions/cache — key design, restore-keys fallbacks, branch scoping, size quotas and eviction, and the cache-poisoning risk to avoid.
- Lesson 9: 09. ArtifactsUpload, download and manage workflow artifacts — retention, size and storage cost, passing output between jobs, immutability, and what must never be uploaded.
- Lesson 10: 10. EnvironmentsUse environments to gate deployments — protection rules, environment secrets and variables, branch and tag restrictions, deployment URLs and history.
- Lesson 11: 11. Deployment ApprovalsRequire human approval before a deployment — reviewers, wait timers, branch restrictions, what approval does and does not verify, and designing gates people read.
Cache and artifact are not the same thing
Section titled “Cache and artifact are not the same thing”Both store files between jobs. Confusing them produces both broken pipelines and real security problems, so the distinction appears here and in both lessons.
| Cache | Artifact | |
|---|---|---|
| Purpose | Make future runs faster | Preserve output |
| May vanish | Yes — evicted at any time | No, until retention expires |
| A miss is | Normal; the job continues | A failure |
| Scope | Shared across branches by rules | The workflow run |
| Contents | Reproducible dependencies | Build results, reports |
| Safe for sensitive data | No | No |
A cache is an optimisation you must be able to lose. An artifact is a result you meant to keep.
Using a cache for build output means a run that misses produces nothing. Using an artifact for dependencies means paying storage for something you could re-download.
When to reach for each reuse mechanism
Section titled “When to reach for each reuse mechanism”Three mechanisms, and the decision is usually clear once framed as a question about scope.
A composite action when the same steps repeat inside jobs. Setting up a toolchain, configuring credentials, a build-and-verify sequence. It runs in the caller’s job and shares its runner.
A reusable workflow when the same jobs repeat across repositories. An entire CI pipeline, a deployment sequence. It brings its own jobs and runners.
A custom action when neither fits — you need behaviour no combination of existing steps provides, or you want to distribute something to people outside your organisation.
The progression matters: most teams should exhaust composite actions before writing a reusable workflow, and exhaust both before writing a JavaScript or Docker action. Each step up costs more to maintain, and the maintenance is permanent.
The cost of centralisation
Section titled “The cost of centralisation”Reusable workflows are presented as unambiguously good, and they carry real trade-offs worth stating.
A shared workflow is a shared dependency. A breaking change to it breaks every consumer simultaneously. Version it, and let consumers pin.
It is also shared attack surface. A compromised shared workflow reaches every repository that calls
it, with whatever secrets they pass. This is the strongest argument for naming secrets explicitly
rather than using secrets: inherit across an organisation.
It hides what runs. A repository whose entire pipeline is uses: org/workflows/ci.yml@v2 is
readable in one line and opaque in every other sense. Someone auditing it must go elsewhere.
It resists local variation. The team that needs one extra step now needs the shared workflow to grow an input, or to stop using it. Shared workflows accumulate inputs for exactly this reason.
None of that argues against centralising — for thirty repositories with identical needs it is clearly right. It argues for doing it deliberately, with versioning, and for keeping the shared thing as small as the shared need actually is.
Runner selection, summarised
Section titled “Runner selection, summarised”The decision most often made for the wrong reason.
| Need | Answer |
|---|---|
| Standard Linux, Windows or macOS builds | GitHub-hosted |
| ARM64 builds and tests | GitHub-hosted ARM labels |
| More cores or memory than standard | Larger runners — Team and Enterprise Cloud |
| GPU workloads | Larger GPU runners where available, or self-hosted |
| Access to a private network | Self-hosted, necessarily |
| Specific licensed software | Self-hosted |
| Unusual hardware | Self-hosted |
| “It would be cheaper” | Reconsider |
The last row is the one worth arguing about. Self-hosting shifts cost from a bill to an operational burden: patching, monitoring, scaling, and a security posture that GitHub was previously providing. For an organisation that already operates infrastructure, that may be a good trade. For a team that does not, it usually is not — and the security consequences of a badly-run runner are considerably more expensive than the minutes it saved.
Then what?
Section titled “Then what?”The Security cluster is the natural continuation, and it is not optional for anything in this one. Self-hosted runners, custom actions and reusable workflows each expand what a compromise could reach — a shared workflow is shared attack surface, and a runner you operate is a machine you must defend.## Prerequisites, restated
This cluster assumes you can write and debug a workflow without reference, and that you have a real pipeline to improve. Every lesson starts from a problem rather than a feature, and the problems only make sense once you have run into them.
If you are here before building anything, Fundamentals and then a pipeline from Continuous Integration will make this cluster far more useful.
A note on complexity
Section titled “A note on complexity”Every feature in this cluster adds something to maintain. A matrix is more configuration than one job; a reusable workflow is a shared dependency; a self-hosted runner is a machine to patch.
The useful discipline is to add each one in response to a problem you can name, and to be willing to remove it when the problem goes away. A repository carrying a reusable workflow, three composite actions and a self-hosted runner for a pipeline that builds one small service has more machinery than it has need.
Begin: Matrix Builds