4.2 Comparing Reusable Workflows, Composite Actions & Starter Workflows
Key Takeaways
- Reusable workflows operate at the job level, provision their own runner instances, support multi-job DAGs, and allow secret inheritance (secrets: inherit).
- Composite actions operate at the step level within the caller's existing runner, grouping multiple command steps and actions into a single portable action definition.
- Starter workflows are organization-wide templates stored in .github/workflow-templates that developers copy into their repositories during initial project scaffolding with no ongoing upstream link.
- Composite actions require an explicit shell: declaration on every run: step and cannot access repository secrets directly without caller-provided inputs or step environment variables.
- Workflow templates are offered only to repositories whose visibility matches or is more restricted than the `.github` repository holding them, and non-public template repositories additionally require Read access; disabling a workflow is a reversible setting that preserves run history, while deleting the file is a commit that removes the definition entirely.
Comparing Reusable Workflows, Composite Actions & Starter Workflows
When designing a scalable CI/CD strategy across an enterprise, modular code reuse is paramount. GitHub Actions provides three distinct architectural mechanisms for code and pipeline reuse:
- Reusable Workflows (
workflow_call): Job-level pipelines that orchestrate end-to-end multi-job processes across isolated runners. - Composite Actions (
runs.using: 'composite'): Step-level actions that bundle multiple shell commands and action steps into a single reusable component executed on the caller's existing runner. - Starter Workflows (
.github/workflow-templates): Organization-level workflow templates that developers copy into their repositories as boilerplate when creating new workflows in the GitHub UI.
Selecting the correct reuse mechanism requires understanding their operational boundaries, execution contexts, security models, and lifecycle maintenance characteristics.
1. Comprehensive 10-Criteria Comparison Matrix
The following comparison table highlights the precise technical differences across all ten core dimensions tested on the GH-200 exam:
| Technical Criterion | Reusable Workflow (workflow_call) | Composite Action (composite) | Starter Workflow (workflow-templates) |
|---|---|---|---|
| 1. Level of Abstraction | Job Level (invoked under jobs.<job_id>.uses) | Step Level (invoked under steps[*].uses) | Repository Level (copied template file) |
| 2. Runner Allocation | Allocates its own runner(s) per job definition (runs-on) | Runs inside the caller job's existing runner | Defined in generated YAML; runs on caller's runners |
| 3. Multi-Job Pipelines / DAG | Yes: Can define multiple jobs coordinated via needs | No: Limited strictly to sequential steps within a single job | Yes: Can define any full workflow structure |
| 4. Secret Handling | Supports secrets: inherit and explicit typed secrets | No direct secret access; must pass as inputs or env | Secrets must be configured in target repository |
| 5. Matrix Strategy | Caller can invoke reusable workflow across a strategy.matrix | Action executes inside a matrix step if caller job defines it | Matrix can be coded into template file |
| 6. Environment Approvals | Supports GitHub environment: protection rules per job | Cannot bind to environments directly | Can reference environments in copied YAML |
| 7. Code Linkage & Updates | Live Link: Upstream updates immediately take effect | Live Link: Upstream updates immediately take effect | Disconnected Copy: No link after initial creation |
| 8. Nesting Capability | Up to 10 levels of workflows; max 50 unique reusable workflows per file | Can call other actions (JS, Docker, Composite) | Cannot nest templates |
| 9. Shell Specification | Shell is optional for run: steps (uses runner default) | Mandatory: Every run: step must specify shell: | Shell is optional on generated run: steps |
| 10. Primary Enterprise Use | Enterprise compliance gates, standard release pipelines | Reusable setup routines, multi-step CLI scripts | New repository scaffolding and onboarding presets |
2. Deep Dive: Composite Actions vs. Reusable Workflows
Because both Reusable Workflows and Composite Actions provide version-controlled, centralized code reuse, choosing between them is a frequent enterprise design challenge.
When to Choose a Composite Action
- Shared Setup Sequences: You need to execute 4-6 sequential steps (e.g., checkout code, setup Go/Node toolchain, restore cache, run linting) inside the same runner without paying the provisioning overhead of starting a new virtual machine.
- File System State Sharing: The steps must mutate the local workspace (e.g., compile code, generate local
.envconfiguration) so that subsequent steps in the caller job can immediately read the files on disk. - Action Ecosystem Distribution: You want to package your tooling to publish to the GitHub Marketplace or share across heterogeneous workflows as a modular building block.
# action.yml (Composite Action)
name: 'Setup & Authenticate Toolchain'
description: 'Configures custom enterprise build utilities'
inputs:
api-token:
description: 'Auth token'
required: true
runs:
using: 'composite'
steps:
- name: Download CLI
shell: bash # MANDATORY in composite actions!
run: curl -s https://bin.corp.internal/tool -o /usr/local/bin/tool
- name: Authenticate
shell: bash # MANDATORY!
run: /usr/local/bin/tool login --token "${{ inputs.api-token }}"
When to Choose a Reusable Workflow
- Complete Multi-Job Lifecycles: The process consists of multiple discrete phases (e.g.,
lint->build->security-scan->deploy-prod) requiring independent runner environments (such as Ubuntu for building and Windows/macOS for packaging). - Centralized Compliance Gates: Security teams require mandatory security scanning and deployment verification that individual developers cannot modify, omit, or tamper with.
- Environment Protection Rules & Approvals: The process must deploy to protected environments (
production) that require manual reviewer approvals and deployment branch restrictions.
3. Starter Workflows: Enterprise Scaffolding
Starter workflows reside in a special repository named .github in an organization or enterprise account under the .github/workflow-templates/ directory.
Anatomy of a Starter Workflow
A starter workflow requires two files in the .github repository:
- The Workflow Definition File (
.github/workflow-templates/nodejs-ci.yml): Contains the template YAML. Can include$default-branchplaceholder tokens which GitHub replaces with the repository's default branch upon creation. - The Metadata Properties File (
.github/workflow-templates/nodejs-ci.properties.json): Describes the template in the GitHub Actions template picker UI:{ "name": "Node.js Enterprise CI", "description": "Standard corporate Node.js build, test, and security scan.", "iconName": "nodejs", "categories": ["Node", "CI"], "filePatterns": ["package.json", "tsconfig.json"] }
The Disconnected Nature of Starter Workflows
When a developer creates a new workflow from a starter template, GitHub copies the YAML file directly into their repository's .github/workflows/ directory.
[!WARNING] Once copied, there is zero ongoing connection between the starter template and the repository's workflow file. If the enterprise updates the starter template in the
.githubrepository, existing repositories will not receive the update automatically. For managed, enforceable standards, use Reusable Workflows instead.
Non-Public .github Repositories: Template Visibility Rules
The .github repository holding your templates does not have to be public. GitHub Actions supports workflow templates from non-public .github repositories, and the repository's visibility determines who can consume the templates:
Visibility of the .github repository | Templates are offered in... |
|---|---|
| Public | All repository types - public, internal, and private |
| Internal | Internal and private repositories only |
| Private | Private repositories only |
The rule is simple: a template is available to repositories whose visibility matches or is more restricted than the template repository. A public .github repository reaches everything; a private one reaches only private repositories.
[!IMPORTANT] Read access is the gate for non-public templates. If your
.githubrepository is private or internal, users and teams must be granted Read access to it before the templates appear in their "New workflow" picker. A regulated organization that keeps its CI scaffolding private and then forgets this grant will find the template list mysteriously empty for most engineers - the templates exist, but the consumers cannot see the repository.
Two mechanics carry over regardless of visibility:
- The
$default-branchplaceholder is substituted with the consuming repository's real default branch name when the workflow is created, so a template does not have to hard-codemain. - The
.properties.jsonmetadata file must share the workflow file's base name.octo-organization-ci.ymlpairs withocto-organization-ci.properties.json;nameanddescriptionare required, whileiconName,categories, andfilePatternsare optional.filePatternsis a regular expression matched against files in the consuming repository's root, so a template can be surfaced only to repositories that actually contain, say, apackage.json.
4. Disabling versus Deleting a Workflow
The blueprint asks you to contrast disabling and deleting workflows, and the exam scenario is nearly always "how do we stop this from running without losing the history?"
| Dimension | Disable workflow | Delete workflow file |
|---|---|---|
| What you do | Actions tab -> select the workflow -> ... menu -> Disable workflow (or PUT /repos/{owner}/{repo}/actions/workflows/{workflow_id}/disable) | Remove the .yml file from .github/workflows/ in a commit |
| Requires a commit? | No - it is a repository setting, and the YAML file stays in the branch | Yes - it is a code change and goes through your normal review and ruleset gates |
| Effect on future triggers | No new runs start; the workflow is listed as disabled with an explicit banner | No new runs start because the definition no longer exists on the branch |
| Effect on run history | Preserved and visible in the Actions tab | The workflow disappears from the sidebar; historical run records are no longer surfaced alongside it |
| Reversibility | One click - Enable workflow restores it immediately | Requires restoring the file through a new commit or a revert |
| Required status checks | A required check backed by a disabled workflow will never report, so pull requests can stall in a pending state | Same failure mode, plus the ruleset now names a check that no repository workflow can produce |
| Typical use | Pausing a noisy or failing scheduled job, freezing deployments during an incident, temporarily stopping a workflow while you debug it | Permanently retiring a pipeline that has been replaced |
[!TIP] Prefer disabling for anything temporary. Disabling is reversible, leaves an auditable record, and does not touch protected-branch history. Also remember the separate, automatic case: GitHub disables scheduled workflows automatically after 60 days of repository inactivity, and the owner must re-enable them manually - a disabled workflow is not always something a human chose.
[!WARNING] Both actions can deadlock a pull request. If a branch ruleset requires the
build-and-teststatus check and you disable or delete the workflow that produces it, open pull requests wait forever on a check that will never report. Remove the required status check from the ruleset in the same change.
A central platform engineering team needs to enforce a mandatory, multi-job deployment pipeline across 200 microservice repositories. The pipeline must run static analysis, build a container on a Linux runner, execute integration tests on a Windows runner, and require manual approval before deploying to an environment named 'production'. When the central team updates the pipeline logic, all 200 repositories must immediately inherit the changes without manual intervention. Which mechanism must be selected?
An engineer is authoring a component to bundle four repetitive setup steps into a single reusable unit that executes directly inside the calling job's existing virtual runner without provisioning new runner infrastructure. Which reuse mechanism should the engineer build?
When developing a Composite Action in action.yml, what syntax requirement must be included on every run: step that is not strictly required in standard workflow files?