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 | Private daemon in a lightweight VM with its own kernel | 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-sysboxandisolated-katagive each runner its own nested Docker daemon with real isolation.
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.