Runner Group
A runner group is a GitHub-side container around a set of runners that controls which repositories and which workflows are allowed to run jobs on them.
A runner group is a container defined on the GitHub side that holds a set of runners and carries an access policy describing which repositories may use them. The same policy can narrow access further to named workflow files at a specific branch, tag, or commit SHA, so a group answers the question of who is allowed to run jobs on this hardware.
The term shows up in two places: in the organization or enterprise settings where the group and its policy are edited, and in the runs-on key of a workflow when a job wants to target one group by name.
Definition
A runner group has three parts.
- A name. The string a workflow uses to target the group, and the string that appears in the settings list.
- A membership list. The runners assigned to the group. A runner belongs to exactly one group at a time, and moving it to another group changes which repositories can reach it.
- An access policy. The rules that decide which repositories, and optionally which workflows, may queue jobs onto the members.
The policy is evaluated by GitHub before any label matching happens. A repository that the policy excludes never sees the runners inside the group, whatever labels those runners advertise.
Where groups sit in the runner hierarchy
Registration scope decides whether a group is involved at all. A runner is registered against one repository, one organization, or one enterprise, and only the last two put the runner into a group.
| Registration scope | Group applies | Who edits the policy | What the policy controls |
|---|---|---|---|
| Repository | No | Repository admins | The runner serves that one repository |
| Organization | Yes | Organization owners | Which repositories in the organization may use the group |
| Enterprise | Yes | Enterprise admins | Which organizations may use the group, and then which repositories inside them |
Enterprise groups nest. An enterprise group first chooses the organizations that can see it, and each of those organizations then chooses the repositories that can use it. A repository needs a yes at both levels.
Groups are not limited to runners you supply. GitHub places its own larger hosted runners into groups as well, and access to a larger runner shape is administered through the same repository access policy (GitHub larger runners reference, checked on 2026-08-13).
What a group can restrict
GitHub supports a small, fixed set of restriction axes. Every axis is a filter on eligibility, and a job has to pass all of them.
| Axis | Values GitHub supports | Typical use |
|---|---|---|
| Repository access | All repositories in the organization, or a selected list | Keep a fleet reserved for one team's repositories |
| Public repositories | Allowed or disallowed, disallowed by default | Decide whether self-hosted runners may serve public repositories |
| Organization access | All organizations, or a selected list (enterprise groups only) | Share one enterprise fleet with named organizations |
| Workflow path | All workflows, or named workflow files | Allow only the deployment workflow onto a privileged fleet |
| Branch, tag, or sha | A ref appended to the workflow path | Allow the deployment workflow only from the release branch |
A workflow restriction is written as a full path with a ref attached. The form is owner/repo/.github/workflows/cd.yaml@refs/heads/main for a branch, @refs/tags/v1 for a tag, and a commit SHA for an exact revision. Adding one restricted workflow to a group blocks every workflow the list does not name, which is why the symptom of a workflow restriction is one file queueing while the rest of the repository keeps working (WarpBuild common issues documentation, checked on 2026-08-13).
How a group is chosen when a job queues
The runs-on key accepts an object form that names a group and then filters inside it:
jobs:
deploy:
runs-on:
group: production-runners
labels: [self-hosted, linux, x64]Evaluation runs in two stages. GitHub first builds the candidate set: the runners inside production-runners, provided the group's policy grants this repository access. It then applies the ordinary label rule inside that set, where a runner is eligible only when it carries every label the job asked for. Extra labels on the runner are ignored, which is covered in more detail under runner label.
A job that names no group skips the first stage and is eligible for runners in any group the repository can reach, plus any runner registered directly against the repository. Most workflows are written this way, which is why teams often meet the concept for the first time while debugging a job that never started.
The group name is checked against the groups the repository can reach. Naming a group that exists but excludes the repository, and naming a group that does not exist at all, produce the same visible result: the job stays queued and the log stays empty. GitHub cancels a job that has been queued for 24 hours (GitHub Actions limits, checked on 2026-08-13), so a policy mistake reports itself a day after the push.
Groups are editable through the REST API as well as the settings UI, under the organization and enterprise runner group endpoints (GitHub REST API for self-hosted runner groups, checked on 2026-08-13). That is the path teams use to keep the repository access list in version control rather than in a browser tab.
Example
Every organization starts with one group called Default, carrying id 1. It cannot be deleted, and a runner registered at the organization level lands in it unless an admin moves the runner somewhere else. Managed runner fleets follow the same rule, because a provider registers machines against your organization through the same GitHub registration API a self-hosted runner uses. WarpBuild registers into the Default runner group at id 1 (WarpBuild public repositories documentation, checked on 2026-08-13).
The Default group is where the public repository setting lives, and that single checkbox is the most consequential policy toggle in the whole feature. GitHub disables self-hosted runners in public repositories by default. Until an organization owner opens the group settings page and checks Allow public repositories, every job in every public repository that targets a self-hosted or managed runner queues and never starts, while the same workflow in a private repository in the same organization runs normally.
That asymmetry is worth stating plainly, because the workflow file is identical in both cases. The difference lives entirely in the group policy.
A job before and after the group is opened
Start with a workflow that names no group. It asks for a runner by label, and eligibility is decided by whichever groups the repository can reach:
name: build
on:
push:
branches: [main]
jobs:
unit-tests:
runs-on: warp-ubuntu-latest-x64-4x
steps:
- uses: actions/checkout@v4
- run: make testIn a private repository whose organization has this fleet in the Default group, the job is claimed and starts. In a public repository in the same organization, the identical job stays queued until Allow public repositories is checked on that group. Nothing in the file changes between those two outcomes.
Once an organization creates a second group, jobs can target it explicitly. The object form pairs the group name with the labels used inside it:
name: release
on:
push:
tags: ['v*']
jobs:
build-linux:
runs-on:
group: release-runners
labels: [warp-ubuntu-latest-x64-8x]
steps:
- uses: actions/checkout@v4
- run: make release
build-linux-arm:
runs-on:
group: release-runners
labels: [warp-ubuntu-latest-arm64-4x]
steps:
- uses: actions/checkout@v4
- run: make releaseBoth jobs are filtered by the group first and the label second. If release-runners excludes this repository, neither job starts, and the label is never consulted. If the group grants access but carries a workflow restriction of acme/service/.github/workflows/release.yaml@refs/tags/v1, then a push of tag v2 queues while v1 runs, because the ref in the restriction is part of the match.
The labels in those two files resolve to the machine shapes below. Sizes are from the WarpBuild cloud runners documentation, checked on 2026-08-13.
| Label | OS | vCPU | RAM | Storage |
|---|---|---|---|---|
warp-ubuntu-latest-x64-4x | Ubuntu 24.04 | 4 | 16 GB | 150GB SSD |
warp-ubuntu-latest-x64-8x | Ubuntu 24.04 | 8 | 32 GB | 150GB SSD |
warp-ubuntu-latest-arm64-4x | Ubuntu 24.04 | 4 | 16 GB | 150GB SSD |
Reading the failure from the outside
A group problem and a hardware problem look the same on the Actions tab for the first minute. They separate over time. A job waiting on busy runners is claimed as soon as one frees up, and its log fills in. A job blocked by a group policy is never claimed, so the log view stays empty until the 24 hour cancellation. Waiting longer changes nothing, because the passage of time does not add the repository to an access list.
Three checks resolve almost every instance, in the order the causes actually occur: confirm the repository is public or private and read the public repository checkbox on the group; confirm the repository appears on the group's repository access list; then read the workflow restrictions for a path or ref that excludes this file. The runner groups guide walks each check with the settings pages involved.
Related Terms
- Using runner groups with GitHub Actions: the troubleshooting checklist for a job that never starts, in the order the causes occur.
- Runner label, defined: the subset matching rule that runs after group filtering, and the label shapes that encode a machine size.
- Self-hosted runner, defined: what registration scope means and why organization-level registration is what puts a runner into a group.
- Are GitHub Actions free for open source?: what a public repository gets by default, and where the public repository setting on a group fits.
- WarpBuild public repositories documentation: the
Defaultgroup at id1and theAllow public repositoriescheckbox, with the settings page path. - WarpBuild common issues documentation: runner group access checks and the workflow restriction syntax with a worked example.
- WarpBuild pricing: per minute rates by runner type.
FAQ
What is a runner group in GitHub Actions?
A runner group is a container defined on the GitHub side that holds a set of runners and carries an access policy. The policy decides which repositories may send jobs to those runners, and optionally which workflow files, branches, tags, and commit SHAs may claim them. Every runner registered at the organization or enterprise level belongs to exactly one group.
Do runner groups apply to repository-level runners?
Groups are an organization and enterprise concept. A runner registered against a single repository is already scoped to that repository, so there is no group policy to apply. Once a runner is registered at the organization or enterprise level, it lands in a group, and the group's access policy decides which repositories can reach it.
How does a workflow target a specific runner group?
Use the object form of runs-on with a group key, for example runs-on with group set to production-runners and labels set to [linux, x64]. GitHub first narrows the candidate runners to that group, then applies the usual label subset match inside it. A job that names no group is eligible for any group the repository can reach.
Why does a job stay queued when a runner group excludes the repository?
No runner is eligible, so nothing claims the job and nothing writes to the log. The run sits at the waiting state with an empty log view for as long as you let it. GitHub cancels a job that has been queued for 24 hours, so the failure surfaces a day later rather than immediately.
Start with $10 in free credits
Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.