Configuring Workloads
A workload is a pool of ephemeral runners attached to one GitHub organization or
personal account. It holds the targeting, sizing, runtime, cache key, and host
pool; the runner’s shape lives in a separate runner
profile it references. Create a workload from
the Add workload dialog; edit it later from /workloads/<id>.
Organization or account
Section titled “Organization or account”The connected GitHub organization or personal account this pool serves. The account must already be added with a valid classic PAT — see the quickstart. One account can back many workloads; one workload serves exactly one account.
Runner profile
Section titled “Runner profile”The runner profile this workload uses for the runner’s shape — image, memory and CPU limits, custom env, pull policy, and an optional registry credential. A profile is reusable: many workloads can point at the same one, so you define the shape once. Editing a profile applies to each referencing workload on its next reconcile pass (new spawns only).
Sizing: minRunners and maxRunners
Section titled “Sizing: minRunners and maxRunners”Runaway sizes the pool to demand between two bounds:
-
minRunners— the warm floor kept ready even when the queue is empty. -
maxRunners— the ceiling Runaway scales up to under load. -
Scale to zero —
minRunners = 0. No runners sit idle; the pool spins up when work arrives. -
Warm pool —
minRunners = NkeepsNrunners ready, trading idle capacity for lower start latency. -
Fixed pool —
minRunners = maxRunnerspins the pool to a constant size.
For how demand is measured, see Autoscaling.
Labels and job routing
Section titled “Labels and job routing”GitHub routes a job to a runner when the job’s runs-on labels are a subset of
the runner’s labels. Give each workload a distinct label and match it in your
workflow:
jobs: build: runs-on: [self-hosted, my-label]Runtime
Section titled “Runtime”Each workload runs on exactly one runtime tier. The tier decides how much Docker access, and how much isolation, its runners get.
| Tier | Docker access | Isolation | Host requirement |
|---|---|---|---|
| none (default) | None inside runners | n/a | None |
| shared-daemon | Shares the host daemon via a bind-mounted socket (DooD) | None | None |
| dind | Private privileged inner daemon per runner | Process-level only | None |
| isolated-sysbox | Private nested daemon per runner (user-namespaced) | Strong | sysbox-runc installed |
| isolated-kata | None inside runners — VM isolation only | Strongest | kata runtime + /dev/kvm |
noneis the safe default — runners have no Docker access at all.shared-daemongives maximum cache reuse but no isolation. GitHubcontainer:andservices:jobs do not work here.dindworks anywhere and supportscontainer:/services:, but privileged means a container escape is host-root. It requires an explicit acknowledgement and is only for trusted, single-tenant CI.isolated-sysboxgives each runner its own nested Docker daemon with real isolation.isolated-kataruns each runner in a VM with its own kernel, and starts no inner daemon — for Docker jobs pickdindorisolated-sysbox.
Which tier does my job need?
Section titled “Which tier does my job need?”The table above describes what each tier is. This one starts from what your jobs already do:
| If your workflow… | Pick | Because |
|---|---|---|
| runs no Docker at all | none | Nothing to grant, so grant nothing. |
| uses services: or container: | dind or an isolated tier | The runner needs its own daemon; on shared-daemon a service publishes to the host and the job looks for it on its own loopback. |
| runs docker build or docker run, trusted code only | shared-daemon | Fastest, and the image cache is shared across runs. Expect to adapt the workflow. |
| bind-mounts anything outside the workspace | a nested tier | On shared-daemon only $GITHUB_WORKSPACE exists on both sides. |
| builds images on untrusted PRs | isolated-sysbox | A privileged inner daemon and a host socket are both host-root on escape. |
| must not share a kernel | isolated-kata | VM isolation, at the cost of no inner daemon. |
A workflow written for ubuntu-latest and moved to shared-daemon usually needs
real changes; the same workflow on a nested tier usually needs almost none. See
Converting an existing workflow for what
that costs before you choose.
See Isolated runtime for the nested tiers and their host setup.
Cache key
Section titled “Cache key”A workload selects a host-owned cache volume with an optional cache key. With no key, all same-org workloads on a host share one organization cache; with a key, they get a separate warm cache. Different organizations never share a cache. See Caching for how the volume is resolved.
Target hosts and per-host caps
Section titled “Target hosts and per-host caps”Assign the workload to one or more enrolled hosts from Edit hosts. The scheduler distributes runners across every targeted host, bounded by a per-host cap and by each host’s shared runner-capacity budget. See Running multiple hosts.