What Is a Runner in GitHub?

What Is a Runner in GitHub?

A thorough, zero-prior-knowledge walkthrough of the actual machine that executes your automation — where it comes from, what it can and can't do, and how to choose between GitHub's own runners and your own.

Imagine you’ve written detailed instructions for assembling a piece of furniture — step by step, perfectly clear. Those instructions are useless on their own; someone, or something, actually has to stand at a workbench, with the right tools in reach, and physically carry them out. In GitHub Actions, a workflow file is the instructions — but a runner is the workbench itself: the real, physical (or virtual) computer where every step actually executes. In this guide, we’ll build up the idea of a runner completely from zero — what it is, why it needs to exist as its own distinct concept, exactly what happens on one behind the scenes, and how to choose between the runners GitHub provides and ones you manage yourself.

1Core Concepts: What a Runner Actually Is

Before any configuration details, let’s build a precise, plain-language definition.

What it is: A runner is the actual server — a real or virtual computer — that executes the steps of a job in a GitHub Actions workflow. When a workflow says “run this command” or “use this action,” the runner is the machine where that command genuinely runs and produces a real result.

Why it exists: A workflow file is only a description of what should happen — it contains no computing power of its own. Something has to provide an actual operating system, disk space, memory, and processing power to carry out each step for real. A runner exists to be exactly that: the concrete execution environment underneath the abstract instructions written in a workflow file.

Where it’s used: Every single job in every GitHub Actions workflow runs on some runner — there’s no such thing as a job without one. What varies is where that runner comes from: a machine GitHub itself provides and manages, or one an individual or organization sets up and maintains themselves.

Everyday Analogy

Think of a runner like a rented conference room for a one-time meeting. You don’t own the room, you don’t maintain it, and once your meeting ends, it’s cleaned and made ready for someone else’s completely unrelated meeting — with nothing of yours left behind. A GitHub-provided runner works exactly this way: a fresh, temporary machine, used once for your job, and then discarded entirely.

Practical example: A team’s workflow includes a job that needs to install a specific programming language, download the project’s code, run its test suite, and report the results. All of this genuinely happens — files are actually downloaded, processes actually run, memory is actually used — on a runner machine that GitHub allocates the moment the job starts, and discards once it finishes.

2The Problem & Motivation Behind Runners

Like every infrastructure concept, the runner exists because of a very real, practical limitation that came before it.

Before automation platforms like GitHub Actions existed, teams needing to automatically test or build their software after every code change typically had to set up and maintain their own dedicated servers for that purpose — installing an operating system, keeping it updated, securing it, and making sure it always had enough capacity for however much automation the team needed to run. This was a real, ongoing operational burden, separate from the team’s actual software work.

The concept of a runner — specifically, a runner that GitHub itself can provide on demand — solves this by shifting that operational burden onto GitHub. Instead of a team owning and maintaining a server, GitHub allocates a brand-new, ready-to-use machine the instant it’s needed, and removes it the instant the job is done, so no one has to think about server maintenance at all for standard automation needs.

i
Key Insight

The word “runner” refers specifically to the machine doing the work — not the workflow, not the job, and not the automation logic itself. A job is “what should happen”; a runner is “the computer where it actually happens.” Keeping this distinction clear makes many other GitHub Actions concepts click into place more easily.

The core problem runners solve: automation needs somewhere real to execute, but teams generally don’t want the ongoing burden of owning and maintaining dedicated servers just for that purpose. Runners — especially GitHub-hosted ones — provide that execution environment on demand, without the maintenance responsibility.

3GitHub-Hosted Runners: The Default Option

Most workflows use runners that GitHub itself provides and fully manages, without any setup required from the user.

A GitHub-hosted runner is a virtual machine that GitHub creates, on its own infrastructure, specifically for one job, and then permanently destroys once that job finishes. Because it’s created fresh every single time, it always starts in an identical, predictable, clean state — no leftover files, no configuration drift from a previous job, and no risk that something one job did accidentally affects a completely unrelated later job.

Operating System

Linux

The most commonly used option, offering a wide range of pre-installed developer tools and typically the fastest to start.

Operating System

Windows

Used when a project specifically needs to build or test software intended to run on Windows.

Operating System

macOS

Used when a project needs to build or test software for Apple’s platforms, since certain tools are only available there.

Included Tools

Pre-Installed Software

GitHub-hosted runners come with many common programming languages, package managers, and utilities already installed, reducing setup steps in a workflow.

Choosing which operating system a job runs on is simply a setting in the workflow file — the same job’s steps can even be run once per operating system at the same time using the matrix pattern covered in a related guide on jobs, letting a team verify their software works correctly everywhere it needs to.

4Internal Working: What Happens to a Runner During a Job

Now let’s walk through exactly what happens to a GitHub-hosted runner, from the moment a job needs one to the moment it’s gone.
flowchart LR
    A["Job is ready to start"] --> B["GitHub provisions a fresh virtual machine"]
    B --> C["Runner registers itself and waits for instructions"]
    C --> D["Repository code and any needed setup are downloaded"]
    D --> E["Each step executes on the runner, in order"]
    E --> F["Job finishes (success or failure)"]
    F --> G["Runner machine is permanently destroyed"]
    
FIG 4.1 — The complete lifecycle of a GitHub-hosted runner, from creation to destruction

Step by step, in plain language: first, once a job is ready to begin — meaning any jobs it depends on have already succeeded — GitHub provisions a brand-new virtual machine specifically for it, matching whichever operating system the workflow requested. Second, that machine starts up, registers itself with GitHub as ready to receive work, and waits briefly for its assigned job. Third, the runner typically downloads a copy of the relevant repository code, since almost every job needs it, along with anything else the job’s steps require. Fourth, each step in the job runs on that machine, one at a time, in the exact order defined in the workflow file. Fifth, once every step has run — whether they all succeeded or one of them failed — the job is considered finished. Finally, and importantly, GitHub permanently destroys that specific virtual machine; it’s never reused for a future job, even one from the exact same repository moments later.

?
Why It Matters

This destroy-and-recreate cycle is precisely what guarantees every job starts from a clean, predictable, uncontaminated state — a genuinely valuable property for trustworthy automation, but one that also means anything a job wants to keep — like a compiled package — must be deliberately saved as an artifact (covered in a related guide on jobs) before that runner disappears forever.

5Data Flow & Lifecycle Across a Full Workflow

Zooming out to a complete, multi-job workflow shows how several runners come and go together.
1

Workflow Is Triggered

A push event starts a workflow containing several jobs — say, testing, building, and deploying.

2

Separate Runners Are Provisioned

Each job that’s ready to start gets its own, entirely separate runner machine, even if two jobs run at the exact same time.

3

Each Runner Executes Its Job’s Steps

Every runner works through its assigned job’s steps independently, unaware of what’s happening on any other runner.

4

Finished Runners Are Torn Down

As each job finishes, its runner is destroyed immediately — an earlier-finishing job’s runner doesn’t wait around for slower jobs to catch up.

5

A Later Job Gets a Brand-New Runner

When the “deploy” job becomes ready — because “build” succeeded — it receives its own fresh runner, entirely unrelated to the one “build” used.

Notice that at no point does one job’s runner hand off directly to another job’s runner — they’re entirely separate machines, and any information passed between jobs travels through explicit mechanisms like artifacts, never through the runners themselves persisting or communicating directly.

6GitHub-Hosted Runners vs. Self-Hosted Runners

GitHub-hosted runners aren’t the only option — teams can also run their own runner software on machines they control.

A self-hosted runner is a machine — physical or virtual, on your own premises or your own cloud account — where you personally install and run GitHub’s runner software, registering it with your repository or organization so GitHub can send it jobs, exactly as it would send jobs to one of its own machines. From a workflow’s perspective, the steps run the same way either way; what changes is who owns, configures, and maintains the underlying machine.

GitHub-Hosted Runner

  • No setup or maintenance required
  • Always starts from a clean, identical environment
  • Usage is billed according to GitHub’s own pricing
  • Limited to the hardware and software GitHub provides

Self-Hosted Runner

  • Full control over hardware, installed software, and network access
  • Can reach internal systems a GitHub-hosted runner never could
  • Requires you to maintain, secure, and pay for the machine yourself
  • Does not automatically reset between jobs unless deliberately configured to
!
Warning

Because a self-hosted runner doesn’t automatically wipe itself clean after every job the way a GitHub-hosted one does, files or processes left behind by one job can potentially affect a later job running on that same machine — a meaningful difference to plan around, especially for anything security-sensitive.

7Why Teams Choose Self-Hosted Runners

Given that GitHub-hosted runners are simpler, it’s worth understanding exactly what motivates a team to take on self-hosting instead.

Reaching Internal Systems

A company whose deployment target lives inside a private internal network — not reachable from the public internet at all — sets up a self-hosted runner physically located inside that same network, since a GitHub-hosted runner, living on GitHub’s own infrastructure, would have no way to reach it.

Specialized Hardware Requirements

A team whose automated tests require a specific graphics card or specialized hardware that GitHub’s standard hosted runners don’t offer sets up their own machine with that exact hardware, registering it as a self-hosted runner.

Cost at Very High Volume

An organization running an extremely large number of workflow jobs every day may find that maintaining its own runner machines, at that scale, costs less than paying for the equivalent volume of GitHub-hosted runner usage.

Persistent Caching Needs

A team whose builds benefit enormously from a large, slow-to-recreate cache of downloaded dependencies may prefer a self-hosted runner that can keep that cache between runs, rather than rebuilding it from scratch on every single fresh GitHub-hosted machine.

8Runner Groups & Labels

Larger organizations often need finer control over exactly which runner a given job uses — that’s where labels and groups come in.

Every runner, whether GitHub-hosted or self-hosted, is identified by one or more labels — short tags describing something about it, such as its operating system or a specific capability. A workflow’s job specifies which labels it requires, and GitHub matches the job to any available runner carrying those labels. This is exactly how a workflow requests “a Linux machine” versus “a Windows machine” from GitHub’s own hosted fleet, and it works the same way for self-hosted runners with custom labels of their own.

Organizations with many self-hosted runners often further organize them into runner groups — named collections of runners with shared access rules, letting an administrator control which repositories or teams within the organization are allowed to use which specific runners, an important control when some runners have access to particularly sensitive internal systems.

1+
LABELS
identify what a runner offers
1
GROUP
a self-hosted runner can belong to
N
REPOS/TEAMS
a group’s access can be scoped to

9Advantages, Disadvantages & Trade-offs

Choosing between GitHub-hosted and self-hosted runners — or a mix of both — involves real, concrete trade-offs.
AspectAdvantageTrade-off / Cost
MaintenanceGitHub-hosted runners require zero setup or upkeepSelf-hosted runners demand ongoing maintenance, patching, and monitoring
CleanlinessGitHub-hosted runners always start fresh and identicalSelf-hosted runners can accumulate leftover state unless deliberately reset
Network reachSelf-hosted runners can access private, internal-only systemsGitHub-hosted runners cannot reach anything not exposed to the public internet
CustomizationSelf-hosted runners can use any hardware or pre-installed software you chooseGitHub-hosted runners are limited to what GitHub provides
Cost modelGitHub-hosted usage is billed simply, without infrastructure to manageSelf-hosted runners shift cost toward infrastructure and the effort of running it

The core trade-off to internalize: GitHub-hosted runners trade some flexibility and network reach for near-zero operational burden, while self-hosted runners trade operational responsibility for full control, custom hardware, and access to private systems. Many organizations use both at once — GitHub-hosted for routine, general-purpose jobs, and self-hosted specifically where private network access or special hardware is genuinely required.

10Security Considerations

Because a runner is where code actually executes, it’s one of the most security-sensitive parts of the entire automation system.
!
Warning

Never register a self-hosted runner directly on a public repository that accepts contributions from anyone, without careful additional safeguards. A malicious contributor could submit a pull request specifically designed to run harmful code on that self-hosted machine — and because self-hosted runners often have access to private internal systems or persistent state, the potential impact is far greater than on a temporary, isolated GitHub-hosted machine.

Because a self-hosted runner doesn’t automatically wipe itself between jobs, as covered in Chapter 6, teams that use them often deliberately configure the machine to reset to a clean state after every job anyway, specifically to recover some of the isolation guarantee that GitHub-hosted runners provide by default. This might mean running each job inside its own disposable container or virtual machine on top of the self-hosted infrastructure, rather than executing jobs directly on a long-lived, shared machine.

Runner groups and labels, covered in Chapter 8, are also a genuine security tool, not just an organizational convenience — carefully restricting which repositories or teams can use a runner with access to sensitive internal systems prevents an unrelated, lower-trust project from accidentally or maliciously reaching infrastructure it has no legitimate need to touch.

11Design Patterns & Anti-Patterns

Teams converge on recognizable ways of choosing and organizing runners — some sound, some worth avoiding.

The Hosted-by-Default Pattern starts every new workflow on GitHub-hosted runners, and only introduces self-hosted infrastructure once a specific, genuine need arises — private network access, special hardware, or a proven cost concern at real scale — rather than self-hosting preemptively.

The Scoped-Runner-Group Pattern deliberately organizes self-hosted runners into groups matching trust boundaries, so a runner with access to sensitive production systems is only ever available to the specific, small set of repositories that genuinely need it.

The Container-Isolated Self-Hosted Pattern runs every job inside a fresh, disposable container on top of self-hosted infrastructure, deliberately recreating the clean-slate guarantee of GitHub-hosted runners even on machines the team manages itself.

DECISION — SHOULD A SELF-HOSTED RUNNER SERVE A PUBLIC REPOSITORY? Common Pitfall
The Situation

A team wants faster or more customized automation for a public, open-source repository that accepts contributions from anyone, and considers pointing it at a self-hosted runner they also use internally.

Why This Becomes a Problem

As covered in Chapter 10, an untrusted contributor’s pull request could run arbitrary code on that runner. If it’s the same machine used for internal, sensitive work, a malicious contribution could potentially compromise far more than just that one open-source project.

The Better Pattern

Use GitHub-hosted runners, which are freshly created and destroyed per job, for public repositories accepting outside contributions, and reserve self-hosted runners for private, trusted repositories, or apply strict additional isolation if self-hosting for a public project is truly necessary.

Common anti-patterns to avoid: the Never-Reset Self-Hosted Runner (a long-lived machine that accumulates leftover files and configuration drift across many jobs over time); the Overprivileged Shared Runner (one runner, with broad access to sensitive systems, made available to every repository in an organization regardless of actual need); and the Unnecessary Self-Hosting pattern (maintaining your own runner infrastructure for standard, general-purpose jobs that GitHub-hosted runners would have handled perfectly well, taking on maintenance burden for no real benefit).

12Best Practices & Common Mistakes

A handful of deliberate choices make the difference between a smooth, secure runner setup and a fragile or risky one.
1

Start With GitHub-Hosted Runners

Default to GitHub-hosted runners unless you have a specific, concrete reason to self-host, keeping maintenance burden as low as possible.

2

Never Point Self-Hosted Runners at Untrusted Public Repositories

Keep self-hosted runners restricted to trusted, private work unless you’ve applied real additional isolation.

3

Reset Self-Hosted Runners Between Jobs

Use disposable containers or automated cleanup so a self-hosted machine doesn’t silently accumulate state across unrelated jobs.

4

Use Runner Groups to Enforce Boundaries

Scope access to sensitive self-hosted runners to only the specific repositories or teams that genuinely need them.

5

Match the Operating System to the Real Need

Choose Linux, Windows, or macOS runners based on what your software actually needs to be tested or built for, not by default habit.

Common mistakes beginners make: assuming a self-hosted runner resets itself between jobs the way a GitHub-hosted one does; registering a self-hosted runner on a public repository without considering who might be able to trigger jobs on it; and self-hosting runners for ordinary, general-purpose work that GitHub-hosted runners would have handled just as well, taking on unnecessary maintenance for no real gain.

13Real-World & Industry Examples

Seeing runners chosen and configured in realistic, industry-style scenarios makes the concept concrete.

Open-Source Library Maintenance

A widely used open-source library, accepting pull requests from anyone on the internet, runs all of its automated testing on GitHub-hosted runners specifically because of the isolation they provide by default, protecting the maintainers from any risk an unfamiliar contributor’s code might pose.

Enterprise Deployment to Private Infrastructure

A company deploying software to servers inside its own private data center, unreachable from the public internet, uses self-hosted runners located inside that same network specifically to reach those deployment targets, something a GitHub-hosted runner physically could never do.

Machine Learning Model Training

A team whose automated pipeline needs to train a machine-learning model on a specific type of graphics hardware sets up self-hosted runners with that exact hardware installed, since GitHub’s standard hosted runners don’t offer it.

High-Volume Internal Tooling

A large organization running thousands of internal automation jobs every day maintains its own fleet of self-hosted runners, organized into groups scoped to different internal teams, finding that the investment in infrastructure pays for itself at that volume compared to hosted usage.

14Frequently Asked Questions

Q1Is a runner the same as a job?
No. As covered in Chapter 1, a job is the defined set of steps that should run; a runner is the actual machine where those steps genuinely execute. A job needs a runner to do anything at all.
Q2Does a GitHub-hosted runner get reused for future jobs?
No. As covered in Chapter 4, it’s permanently destroyed once its job finishes, and every future job — even for the same repository — gets a brand-new, fresh machine.
Q3What’s the main reason to use a self-hosted runner instead of GitHub’s?
As covered in Chapter 7, the most common reasons are needing to reach a private, internal-only system, needing specialized hardware GitHub doesn’t offer, or, at very high volume, reducing cost — not simply as a default choice.
Q4Are self-hosted runners automatically as safe as GitHub-hosted ones?
No. As covered in Chapters 6 and 10, a self-hosted runner doesn’t automatically reset between jobs and can carry real risk if exposed to untrusted contributions, unlike a GitHub-hosted runner’s guaranteed clean, disposable environment.
Q5What are runner labels used for?
As covered in Chapter 8, labels let a job specify what kind of runner it needs — such as a particular operating system or capability — and GitHub matches the job to an available runner carrying those labels.
Q6Can an organization use both GitHub-hosted and self-hosted runners together?
Yes. As covered in Chapter 9, many organizations mix both — GitHub-hosted for routine, general-purpose jobs, and self-hosted specifically where private network access or special hardware is genuinely required.

15Summary and Key Takeaways

What to Remember

  • A runner is the actual machine that executes a job’s steps — the concrete computer underneath a workflow’s abstract instructions.
  • GitHub-hosted runners are created fresh for every job and permanently destroyed afterward, guaranteeing a clean, predictable, isolated environment every time, with no maintenance required from the user.
  • Self-hosted runners are machines you register and maintain yourself, offering full control, private network access, and custom hardware — at the cost of ongoing upkeep and responsibility.
  • Runner labels and groups let a workflow request specific capabilities and let organizations restrict which repositories or teams can use particular, sensitive runners.
  • Self-hosted runners carry real security risk when exposed to untrusted, public contributions — a malicious pull request can run arbitrary code on infrastructure you actually own and maintain.
  • Nothing automatically carries over between separate runners, even between jobs in the same workflow — anything needed later must be explicitly saved and passed along.
  • The right choice is usually GitHub-hosted by default, reaching for self-hosted infrastructure only when a specific, genuine need — private access, special hardware, or scale — actually justifies the added responsibility.