Skip to content
compiler.dev

What Is a Self-Hosted Runner? (GitHub Actions)

Last updated

A self-hosted runner is a machine you manage, or rent from a provider, that registers with GitHub and runs your Actions jobs instead of a GitHub-hosted virtual machine. You choose the hardware, operating system and installed tools.

How it works

You install the GitHub runner application on a server, VM or container and register it to a repository, organization or enterprise with a token. The runner opens an outbound connection to GitHub and polls for work. When a job's runs-on labels match the runner's labels, it executes the job locally.

Every runner gets the default labels self-hosted, an OS label (Linux, Windows, macOS) and an architecture label (X64, ARM64). You can add custom labels such as gpu or compiler-ci to target specific machines.

There are two operating styles:

  • Persistent: the runner stays up and runs job after job. Fast caches, but state leaks between jobs.
  • Ephemeral: the runner takes one job (--ephemeral) and is destroyed. Clean, safer, usually autoscaled.

Example

jobs:
  build:
    runs-on: [self-hosted, Linux, X64]
    steps:
      - uses: actions/checkout@v4
      - run: ./gradlew build

When it is worth it

  • You need hardware GitHub does not offer, such as GPUs or specific CPU types.
  • Jobs must reach private networks or on-premise systems.
  • Hosted minutes cost too much at your volume. See GitHub Actions pricing.
  • Builds are slow and you want warm local caches.

The trade-offs are covered in self-hosted vs GitHub-hosted runners. Managed providers give you the benefits without the patching and autoscaling work; compiler.dev is one, and you switch by changing runs-on to [self-hosted, Linux, compiler-ci].

Common mistakes

  • Using persistent runners on public repositories. A pull request from a fork can run arbitrary code on your machine. Avoid self-hosted runners for public repos unless they are ephemeral and isolated.
  • Never cleaning the workspace. Leftover files cause baffling "works on the second run" failures.
  • No autoscaling. A fixed pool leaves jobs queued at peak and idle at night.
  • Skipping updates. Runners that fall far behind the current runner version can stop receiving jobs.
  • Storing long-lived secrets on the host. Prefer OIDC for cloud access. See also securing GitHub Actions.

FAQ

Are self-hosted runners free?

GitHub's pricing for self-hosted runners has changed over time, so check GitHub's current billing page. You always pay for the machines themselves.

Is a self-hosted runner secure?

Only as secure as your isolation. Use ephemeral runners, least-privilege credentials, and do not run untrusted fork code on them.

How do I send a job to one?

Put its labels in runs-on, as a list. The job runs on a runner that has every label in the list.