👋 We've unified all of GitHub's product documentation in one place! Check out the content for REST API, GraphQL API, and Developers. Learn more on the GitHub blog.

Using self-hosted runners in a workflow

To use self-hosted runners in a workflow, you can use labels to specify the runner type for a job.

In this article

For information on creating custom and default labels, see "Using labels with self-hosted runners."

Using self-hosted runners in a workflow

Labels allow you to send workflow jobs to specific types of self-hosted runners, based on their shared characteristics. For example, if your job requires a particular hardware component or software package, you can assign a custom label to a runner and then configure your job to only execute on runners with that label.

To specify a self-hosted runner for your job, configure runs-on in your workflow file with self-hosted runner labels.

All self-hosted runners have the self-hosted label, and you can select any self-hosted runner by providing only the self-hosted label. Alternatively, you can use self-hosted in an array with additional labels, such as labels for a specific operating system or system architecture, to select only the runner types you specify.

For more information, see "Workflow syntax for GitHub Actions."

Using default labels to route jobs

A self-hosted runner automatically receives certain labels when it is added to GitHub Actions. These are used to indicate its operating system and hardware platform:

  • self-hosted: Default label applied to all self-hosted runners.
  • linux, windows, or macOS: Applied depending on operating system.
  • x86, x64, ARM, or ARM64: Applied depending on hardware architecture.

You can use your workflow's YAML to send jobs to a combination of these labels. In this example, a self-hosted runner that matches all three labels will be eligible to run the job:

runs-on: [self-hosted, linux, ARM64]
  • self-hosted - Run this job on a self-hosted runner.
  • linux - Only use a Linux-based runner.
  • ARM64 - Only use a runner based on ARM64 hardware.

The default labels are fixed and cannot be changed or removed. Consider using custom labels if you need more control over job routing.

Using custom labels to route jobs

You can create custom labels and assign them to your self-hosted runners at any time. Custom labels let you send jobs to particular types of self-hosted runners, based on how they're labeled.

For example, if you have a job that requires a specific type of graphics hardware, you can create a custom label called gpu and assign it to the runners that have the hardware installed. A self-hosted runner that matches all the assigned labels will then be eligible to run the job.

This example shows a job that combines default and custom labels:

runs-on: [self-hosted, linux, x64, gpu]
  • self-hosted - Run this job on a self-hosted runner.
  • linux - Only use a Linux-based runner.
  • x64 - Only use a runner based on x64 hardware.
  • gpu - This custom label has been manually assigned to self-hosted runners with the GPU hardware installed.

These labels operate cumulatively, so a self-hosted runner’s labels must match all four to be eligible to process the job.

Routing precedence for self-hosted runners

If you use both repository-level and organization-level runners, GitHub follows an order of precedence when routing jobs to self-hosted runners:

  1. The job's runs-on labels are processed. GitHub then attempts to locate a runner that matches the label requirements:
  2. The job is sent to a repository-level runner that matches the job labels. If no repository-level runner is available (either busy, offline, or no matching labels):
  3. The job is sent to an organization-level runner that matches the job labels. If no organization-level runner is available, the job request fails with an error.

Ask a human

Can't find what you're looking for?

Contact us