Heata Runners: Client Onboarding Guide
Overview
Heata Runners are hosted GitHub Actions runners that execute your CI/CD workflows on Heata's infrastructure. Your jobs run in fully isolated, ephemeral runners that are created fresh for every job and destroyed immediately after.
Switching to heata takes about 10 minutes. Switching back to your previous set up takes just a few minutes.
Prerequisites
- A GitHub organisation (Free, Team, or Enterprise plan)
- Admin access to the organisation
- One or more repositories with GitHub Actions workflows
- Your runner label prefix (provided by Heata during onboarding)
Only have a personal GitHub account? This guide assumes an organisation. If your code lives under a personal account and you'd like to try Heata runners, email techsupport@heata.co — the setup is a little different, and we'll get you going and send you the right instructions.
Step 1: Install the Heata Runner App
-
Go to https://github.com/apps/heata-runners/installations/new
-
Select your GitHub organisation
-
Choose which repositories the App can access:
- All repositories if you want all repos to be able to use Heata runners
- Only select repositories if you want to start with specific repos
-
Click Install
-
After installation, you'll be redirected to a page with a URL like
https://github.com/organizations/yourorg/settings/installations/12345678. Send us the whole URL, not just the number at the end — the number is your installation ID, and the rest of the URL tells us which account it belongs to.
That's it. No API keys, no SSH keys, no tokens to manage. The GitHub App handles all authentication automatically.
What permissions does the App need?
The Heata Runner App requires:
- Actions: Read-only (to see when workflows are queued)
- Self-hosted runners: Read & write (to register ephemeral runners for your org)
The App does not have access to your code, secrets, issues, pull requests, or any other repository content. It can only manage runner registrations.
Step 2: Update your workflow files
Change the runs-on value in your workflow files from a GitHub-hosted runner to a Heata runner.
jobs:
build:
runs-on: yourprefix-heata-standard
steps:
- uses: actions/checkout@v4
- run: npm install
- run: npm test
Replace yourprefix with the label prefix we provided during onboarding.
⚠️ Using Docker? Check for
docker/setup-docker-actionas well.If any of your workflows call
docker/setup-docker-action— often wrapped inside your own composite action, such as.github/actions/setup-docker— that one step needs a guard, or the job will fail on a Heata runner.Heata runners already provide Docker.
setup-docker-actiondownloads Docker CE and starts a second daemon, which cannot set up its own networking in our runner and dies with:failed to register "bridge" driver: failed to create NAT chain DOCKER: iptables --wait -t nat -N DOCKER: Permission denied (you must be root)Because a failing step aborts the whole composite action, every later step in it — Buildx, QEMU, registry logins — is skipped too, so the error you see may point somewhere else entirely.
Add this to the Set up Docker step only:
- name: Set up Docker uses: docker/setup-docker-action@v5 if: ${{ runner.environment == 'github-hosted' }}This is safe to leave in permanently. On GitHub-hosted runners the condition is true, so the step runs exactly as it does today — if you switch back, there is nothing to revert.
Two things to watch:
- Guard only the Set up Docker step. If the same composite also sets up QEMU or Buildx, leave those alone — our runners need them for multi-arch builds, and guarding them will look like a regression.
- Use
runner.environment, notrunner.labels. Labels come back empty on our runners, so acontains()test silently never matches.If you'd like, send us the workflow and we'll tell you exactly which line to change.
Available runner sizes
For simplicity of getting started we provide three tiers. If you have specific needs, please talk to us about custom configurations.
| Tier | vCPU | RAM | Storage | GitHub Equiv. (private repos) | Ideal Use Case |
|---|---|---|---|---|---|
| heata Slim | 1 | 5 GB | 14 GB | ubuntu-slim — 1 vCPU, 5 GB |
Linting, small unit tests, and lightweight automation |
| heata Standard | 2 | 8 GB | 14 GB | ubuntu-latest — 2 vCPU, 8 GB |
Docker builds and heavy integration tests |
| heata Large | 8 | 32 GB | 128 GB | ubuntu-latest-8-cores — 8 vCPU, 32 GB |
Large-scale data processing and monolithic builds |
Examples:
runs-on: yourprefix-heata-slim # lightweight jobs
runs-on: yourprefix-heata-standard # recommended — general purpose
runs-on: yourprefix-heata-large # resource-intensive jobs
You can use different sizes for different jobs in the same workflow:
jobs:
lint:
runs-on: yourprefix-heata-slim
steps:
- uses: actions/checkout@v4
- run: npm run lint
build:
runs-on: yourprefix-heata-large
steps:
- uses: actions/checkout@v4
- run: npm run build
test:
runs-on: yourprefix-heata-standard
steps:
- uses: actions/checkout@v4
- run: npm test
Step 3: Push and verify
- Commit and push the updated workflow file
- Go to the Actions tab in your repository
- You should see your workflow running on a Heata runner
- The runner name will appear as something like
heata-runner-a3f8in the job log
The first runs may take longer than usual while first downloads occur. Subsequent runs benefit from warm caches and should be faster.
That's it
There is no step 4. Your workflows now run on Heata's low-carbon infrastructure.
Optional: Faster caching
Heata runners include a high-speed local cache service on the same physical machine as your runners. To take advantage of it, you can replace actions/cache with our cache action:
Before
- uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
After
- uses: heata-run/cache@v1
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
This is a drop-in replacement. Same syntax, same parameters. The difference is that cache data is stored on local storage rather than GitHub's servers, making cache save/restore significantly faster and with no 10 GB size limit.
Note: The standard
actions/cachestill works on Heata runners. Our cache action is an optional performance upgrade, not a requirement.
Switching back to GitHub-hosted runners
If you ever need to switch back, change runs-on back to a GitHub-hosted runner:
runs-on: ubuntu-latest
That's the only change needed. There are no dependencies, lock-in, or cleanup steps. Your workflows are standard GitHub Actions and work identically on any runner.
Pre-installed software
heata runners aim to be a drop-in replacement for ubuntu-latest. The runner
image is built on Ubuntu 24.04 — the same release ubuntu-latest currently
points at — and a job every Monday compares our installed versions against a
live ubuntu-latest runner, so divergence is caught by us rather than by your
pipeline.
Versions track ubuntu-latest at major.minor. Patch-level differences are
expected and not treated as faults.
Languages and runtimes
| Go | matches ubuntu-latest; 1.24, 1.25 and 1.26 also pre-cached for actions/setup-go |
| Node.js | same version as ubuntu-latest on PATH; 22 and 24 pre-cached for actions/setup-node |
| Python | 3.12 default; 3.10–3.14 pre-cached for actions/setup-python |
| Java | OpenJDK 11, 17 (default) and 21, with JAVA_HOME_11_X64 / _17_ / _21_ set |
| PHP | 8.3 with Composer |
| Ruby | 3.2 with headers |
Build tooling
gcc/g++ 12, 13 and 14 · clang 18 (with clang-format, clang-tidy) ·
make · cmake · ninja · pkg-config · bazel (via bazelisk)
Containers
docker CLI · docker compose · docker buildx (multi-arch builds
supported — see below) · podman · buildah · skopeo
Kubernetes and infrastructure
kubectl · helm · kustomize · kind · minikube · yq · packer ·
pulumi
yq is mikefarah/yq v4, the same
implementation ubuntu-latest ships — not the similarly named Python
yq in Ubuntu's archive, whose syntax is incompatible.
Cloud CLIs
aws · az · gcloud / gsutil · pwsh (PowerShell)
General
git · git-lfs · gh (GitHub CLI) · curl · wget · jq · zip /
unzip · mercurial · postgresql-client · mysql-client
Multi-architecture builds
docker/setup-qemu-action and docker buildx work for linux/arm64 as well
as linux/amd64. Our VMs run a kernel with binfmt_misc available, which is
what QEMU registration requires.
What we deliberately do not ship
ubuntu-latest carries a large amount most pipelines never touch, and we leave
it out to keep runners starting quickly: the Android SDK and NDK, the eleven
bundled .NET SDKs, Swift, Julia, Haskell (GHC/Cabal/Stack), and browsers with
their WebDrivers (Chrome, Chromium, Edge, Firefox, Selenium).
Database servers are also omitted — ubuntu-latest installs PostgreSQL and
MySQL but leaves them stopped, so workflows that need one use a service
container, which works identically here. The clients (psql, mysql) are
installed.
If you need any of these, tell us — they can be added to the image. Anything
else can still be installed in your workflow with apt-get, npm install -g,
pip install and so on, exactly as on ubuntu-latest.
FAQ
How are my workflows kept secure?
Each client's runners operate within their own dedicated, isolated virtual machine, fully separated from all other clients. Within that VM, every job gets a fresh, ephemeral runner that is: - Created from a clean image for each job - Completely destroyed after the job finishes - Unable to access any other client's workloads or data
Your secrets are injected by GitHub directly into the runner, just like with GitHub-hosted runners. Heata never has access to your repository secrets.
Can I use this across multiple repos?
Yes. When you install the GitHub App, you choose which repositories can use Heata runners. Any workflow in those repos can use your yourprefix-heata-* labels. No per-repo setup is needed.
What happens if a runner goes down mid-job?
GitHub will mark the job as failed, and you can re-run it from the Actions tab. The Heata orchestrator automatically cleans up the runner. This is the same behaviour as GitHub-hosted runners.
Is there a concurrency limit?
Yes, your organisation has a configurable maximum number of concurrent runners. Speak to your Heata contact to adjust this. Jobs that exceed the limit are queued and will start as soon as a slot becomes available.
How fast do runners start?
Runners typically boot and are ready to pick up a job within 15-30 seconds of the workflow being triggered. Subsequent runs benefit from local Docker image caching, package manager caching, and warm build caches.
Can I keep using some workflows on GitHub-hosted runners?
Absolutely. You can mix and match. Some jobs can use runs-on: ubuntu-latest (GitHub-hosted) while others use runs-on: yourprefix-heata-standard (Heata) in the same workflow file.
What regions are runners available in?
Heata runners are hosted in the UK and can be used from anywhere in the world. GitHub Actions traffic routes over GitHub's own network, so your workflows will work regardless of where your team is located.
Support
If you have questions or run into issues:
- Email: techsupport@heata.co
- Slack: We can set up a shared channel with your team
- Response time: Within 4 business hours for production issues