Self Hosted vs Hosted CI Runners and Which to Pick
Choose between self hosted and hosted CI runners: cost at scale, speed and caching, special hardware, network access, security risks and maintenance duties.

Hosted runners are easy and billed by the minute. Self-hosted runners are cheaper per minute and give you control, and then the security and the upkeep become yours. The decision is rarely about money alone. It follows comparing CI platforms and the setup in setting up a self-hosted runner. Prices change, so the figures below describe the shape of the trade-off, not current rates.
The trade-off in one table
Hosted Self-hosted
Setup none install, register, patch
Clean per job yes only if ephemeral
Cost model per minute fixed hardware + your time
Break-even low volume high, steady volume
Special hardware limited, extra cost anything you own
Private network needs tunnel/VPN direct access
Caching remote cache local disk cache
Security exposure provider's problem yours
The break-even depends on your usage. A team running a few hundred minutes a month will not save money by hosting a machine, while one burning tens of thousands of minutes may. Include the cost of the person patching the machine, the idle time of the hardware and failed-job debugging.
Reasons to self-host
./config.sh --url https://github.com/example/app --token "$REG_TOKEN" \
--ephemeral --labels linux,arm64,gpu --unattended
./run.shTypical reasons: builds need hardware the provider does not offer (ARM, GPUs, large memory, a specific macOS version); jobs must reach a private network or database; large dependency caches or Docker layers make builds much faster when kept on a local disk; or long jobs would be expensive per minute. The --ephemeral flag makes the runner take one job and then unregister, which restores the clean-slate property. Run it in a container or a throwaway VM per job.
Security: the part that decides
Safe: private repository, trusted contributors, ephemeral runner, no long-lived credentials
Risky: public repository + self-hosted runner (any pull request can run code on your machine)
Dangerous: persistent runner with cloud credentials on disk, shared across projects
A CI job runs arbitrary code from the repository. On a hosted runner that code is isolated in a disposable VM. On a self-hosted runner it runs on your hardware, inside your network, with whatever that machine can reach. Using a self-hosted runner for a public repository allows anyone to open a pull request that executes on it, and both GitHub and GitLab warn against that. Keep runner credentials out of reach with OIDC and short-lived tokens, isolate with containers or VMs, and restrict which repositories and branches can use the runner group.
Maintenance duties
Update the runner software (the platform deprecates old versions), patch the operating system, clear disk space (Docker images, build caches and workspaces fill disks fast, see Docker cleanup), monitor availability, and have a plan for when the only runner dies. Autoscaling with an orchestrator or a cloud-based controller helps with bursty load and gives you ephemeral runners as a side effect. Treat the runner image as code: build it from a definition in the repository rather than by hand.
A hybrid is common
Run most jobs on hosted runners and send the few that need special hardware or private access to self-hosted ones by label. This keeps the maintenance footprint small and the security exposure limited to the jobs that justify it. Re-evaluate when usage changes. Make sure scripts are portable between runners, as in portable CI scripts, so moving a job costs a label change.
Questions to answer before deciding
Start with the workload. What is the monthly volume of build minutes, how many jobs run at the same time at peak, and how long is the longest queue you can tolerate? A team that rarely runs more than two jobs at once does not need an autoscaling fleet, while one that triggers fifty on every push cannot sit behind a single machine. Next, what do the jobs need that hosted runners lack: more memory, a GPU, an ARM or macOS builder, access to a private database or a license server. If the answer is nothing, hosted runners remain the simplest option, and the saving from self-hosting must be large to justify the effort.
Then look at the people. Who patches the runner at midnight when a vulnerability is announced, who watches the disk, and who is on call when the queue stops moving before a release? These are ordinary operations tasks with a real cost in attention. Put a name next to each before buying the hardware.
Isolation models for self-hosted runners
How jobs are isolated decides most of the security story. The weakest model is a long-lived machine that runs jobs directly on the host, where each job can read what the previous one left behind, including caches, credentials and modified tools. A stronger model runs each job in a fresh container, which isolates files and processes but shares the host kernel. The strongest common model starts a fresh virtual machine per job and destroys it afterwards, so nothing survives and a compromised job cannot touch the next. Orchestrators and controllers that scale ephemeral machines on demand provide the last model, with a cost in engineering to set it up.
Whatever the model, restrict network access. A runner needs to reach the CI service and the package registries it uses, and little else. Place it in a separate network segment, block access to internal systems that the job does not need and prohibit access to cloud instance metadata services, which hold credentials for the host's role. A job that can query the metadata endpoint may acquire permissions far beyond its task.
Cost accounting that includes everything
Compare totals, not rates. For the hosted option, take the minutes used, multiply by the rate for the runner size, and add the cost of any larger runners for heavy jobs. For the self-hosted option, add hardware or instance costs, storage, bandwidth, monitoring, backups and the time spent on maintenance valued at a real hourly rate. Include idle capacity: a machine that sits unused sixty percent of the time still costs its full price, which is why ephemeral cloud runners that exist only during jobs often beat dedicated hardware on small teams. Revisit the comparison each year, as prices and usage change.
Moving between the two
Keep the option open by writing pipelines that do not assume either. Select the runner with a label, keep job logic in portable scripts and avoid depending on tools pre-installed on a particular hosted image, installing them through the pipeline with pinned versions instead. A pipeline built this way can move a heavy job to a self-hosted machine by changing one label, or move back when the maintenance burden outgrows the saving. That flexibility is worth more than the best price on either side.
Where this does not apply
For open-source projects, hosted runners are free or nearly so, and the security risk of self-hosting outweighs the savings. For regulated environments with data residency rules, self-hosted may be required regardless of cost. See the GitHub self-hosted runners documentation and the GitLab Runner documentation.


