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.
Related terms
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.
Related
- Self-Hosted vs GitHub-Hosted Runners: Cost and RiskCompare GitHub-hosted, self-hosted and third-party runners on cost, speed, security and upkeep, with a break-even formula and a safe ephemeral setup.
- Hosted Runner Lost Communication With the ServerFix "The hosted runner lost communication with the server" in GitHub Actions: causes like OOM, disk full and killed processes, with steps to diagnose.
- What Are CI Minutes? How Billing WorksCI minutes are the billed compute time your pipelines use. Learn how GitHub Actions counts minutes, multipliers, rounding and how to reduce usage.
- What Is a Cache Key in GitHub Actions?A cache key is the string that identifies a saved cache in GitHub Actions. Learn how keys and restore-keys work and how to avoid stale caches.