Skipbox

runs-on in GitHub Actions: labels, examples, and the one line that cuts your bill

The runs-on line decides two things: the machine your job gets, and what GitHub charges for it. runs-on: ubuntu-latest bills every minute on a private repository, and a team running 20,000 minutes a month on GitHub's 4-core runner pays $222. A self-hosted label bills nothing.

Skipbox is a self-hosted runner without the upkeep. Write runs-on: skipbox and the job runs on your account's own machine for a flat $39 a month, unlimited minutes.

What runs-on takes

runs-on accepts a single label, an expression, a list of labels, or a runner group:

jobs:
  hosted:
    runs-on: ubuntu-latest
  self-hosted:
    runs-on: [self-hosted, linux, x64]
  from-a-group:
    runs-on:
      group: build-runners
      labels: ubuntu-24.04-16core

A list is AND, not OR: the runner must carry every label. A self-hosted runner gets self-hosted, its OS (linux, windows, macOS) and its architecture (x64, ARM, ARM64) by default, plus custom labels you add. A larger runner is reached by the name its organization owner gave it. If no online runner matches, the job waits in the queue, and GitHub fails it after 24 hours.

What your runs-on line costs you

On a private repository, ubuntu-latest is 2 CPUs and 8 GB at $0.006 a minute, and GitHub's 4-core runner is $0.012 a minute. Here is GitHub's 4-core runner against Skipbox's 4 vCPU plan:

GitHub's figures are on GitHub Team, after its included compute. Try your own minutes in the calculator on the home page.

The minutes keep climbing. Coding agents push more often than people, each new test suite adds jobs to every push, and a budget that caps the bill stops your jobs mid-month. Every line that says ubuntu-latest is a meter running.

The self-hosted line, and the work behind it

GitHub bills nothing for self-hosted runner minutes; the charge it announced in December 2025 was shelved the next day. So the cheapest runs-on line is a self-hosted one. Behind it, if you run it yourself, sits a machine you own:

  • servers sized for your builds, and more of them when jobs queue up
  • the OS, Docker and runner application to keep current
  • cleanup between jobs, so one job's credentials and containers never reach the next
  • someone to fix it when it stops taking jobs

Skipbox is that machine, run for you.

Skipbox: one label, no machine to run

A flat price for every size

Minutes are unlimited. Skipbox registers as a self-hosted runner, so its jobs use none of your GitHub minutes and keep running when an Actions budget runs out. Jobs beyond your plan's machines wait their turn.

Faster, because the machine stays

Each plan is a VM kept for your account. Docker images, layers and build cache, package caches and the tool cache stay on its disk between jobs, so the next job starts with them. That is at least 7× the cache room GitHub gives a repository, with no cache keys to maintain.

Nothing to manage

Skipbox updates the image, wipes each job's leftovers, health-checks the machine after every job and rebuilds one that fails. The VMs run Ubuntu 24.04 with Docker, Node.js and Python.

Moving is one line

jobs:
  test:
    runs-on: skipbox # was ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test
  1. Sign in to Skipbox with GitHub.
  2. Install the Skipbox GitHub App and pick the repositories.
  3. Change runs-on and push.

In a matrix, give the Linux leg skipbox and leave Windows and macOS legs on their GitHub labels. To move a job back, change the line back.

Security

  • Each account gets its own machine, for public and private repositories.
  • The runner's credentials, processes and containers are wiped after every job; from 13 November 2026 the checkout and Cargo's target/ stay, so the next build is incremental.
  • Code from people without write access (such as pull requests from forks) runs on a fresh VM that is deleted afterwards.

Try it on your own jobs

The trial is free for 7 days or 3,000 job-minutes, whichever comes first, with no card. Change one runs-on line to skipbox, push twice, and compare the second run with what ubuntu-latest gave you.

FAQ

What does runs-on mean in GitHub Actions?

It names the machine a job runs on: a GitHub-hosted label such as ubuntu-latest, the labels of a self-hosted runner, the name of a larger runner, or a runner group. It also decides the bill, because hosted runners bill per minute and self-hosted runners don't. runs-on: skipbox puts a job on Skipbox, a self-hosted runner at a flat monthly price.

Can runs-on have multiple labels?

Yes, as a list, and a runner must carry all of them: runs-on: [self-hosted, linux, x64] matches only a runner with all three. Skipbox needs one label per job, such as skipbox or skipbox-8x16.

How do I use a self-hosted runner in runs-on?

Give the runner's labels, starting with self-hosted, for example runs-on: [self-hosted, linux, x64]. A runner service gives its machines its own labels: on Skipbox the line is runs-on: skipbox, and Skipbox runs the machine behind it.

What happens if no runner matches runs-on?

The job waits in the queue, and GitHub fails it after 24 hours. A typo in a label queues the job instead of failing it at once, so check the spelling first. On Skipbox, a job beyond your plan's machines also waits its turn and starts as soon as one is free.

How do I use runs-on with a matrix?

Put the labels in a matrix list, such as os: [skipbox, windows-latest, macos-latest], and set runs-on to the matrix's os value. GitHub starts one job per value. A Linux leg can use skipbox while Windows and macOS legs keep their GitHub labels.

Updated November 11, 2026

Faster CI/CD with an always-warm cache

Your warm runner at a flat price

1/12 the cost of GitHub at full use. Flat price, so run it all day. 7× GitHub's cache space.

  • No card
  • Sign in with GitHub
  • Cancel anytime