A runner label is the selector a GitHub Actions job uses in runs-on to find a suitable execution environment. A queued job is assigned only to a runner that is online, available to the repository, and matches every requested label. Labels can identify an operating system, a self-hosted runner, installed tooling, or hardware capacity. section 5.1 section 5.2
Listing 5.1 An example of targeting multiple labels to run the job
jobs:
example-job:
runs-on: [ubuntu-latest, vnet1, sql]
steps:
run: echo 'Job is running on ${{ runner.os }}'
Use an array when a job requires several properties. This job needs an Ubuntu runner that also has both the vnet1 and sql labels; a partial match is not enough. section 5.1
GitHub-hosted runners provide operating-system labels, including ubuntu-latest, windows-latest, and macos-latest, plus version-specific labels such as ubuntu-24.04 or windows-2022. The latest labels are convenient but intentionally move as GitHub changes the underlying image. Pin a version-specific label when a workflow depends on a particular environment; monitor logs and runner-image notices when using latest. section 5.5 section 5.16
Self-hosted runners include the self-hosted label alongside labels derived from their operating system and CPU architecture. Administrators can add labels later through the GitHub UI or API; labels are stored on the GitHub side rather than on the runner. Custom labels cannot contain spaces or exceed 256 characters. section 5.1 section 6.1 section 6.1.1
Use custom labels to expose meaningful execution capabilities without sending ordinary jobs to specialized machines:
- Label GPU-equipped runners gpu and high-memory runners xl, ram-xl, or disk-xl so jobs request only the resources they need. section 6.1.6
- Label runners with required preinstalled tools, such as gh-cli and kubectl, when environments intentionally differ. section 6.1.9
- Use an OS label or a no-space configuration label to target larger GitHub-hosted runners. section 5.11
Treat labels as an operational contract. Keep self-hosted runner definitions uniform where possible, and make exceptional software or hardware explicit through labels. This helps users choose appropriate capacity and can support internal chargeback for expensive runner types. Avoid installing multiple runners on one environment merely to gain concurrency: concurrent jobs can interfere because each runner can access the full environment. section 6.1.6 section 6.1.9
When a workflow remains queued, first verify that its requested labels exist, that a matching runner is available to the repository, and that it is online. Hosted jobs fail after 45 minutes without a matching runner; self-hosted jobs can wait up to 24 hours. A frequent cause is requesting a self-hosted-only label on GitHub-hosted infrastructure. section 5.2 section 6.1.4
