Skip to content

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

  1. Go to https://github.com/apps/heata-runners/installations/new

  2. Select your GitHub organisation

  3. 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
  4. Click Install

  5. 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-action as 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-action downloads 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, not runner.labels. Labels come back empty on our runners, so a contains() 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

  1. Commit and push the updated workflow file
  2. Go to the Actions tab in your repository
  3. You should see your workflow running on a Heata runner
  4. The runner name will appear as something like heata-runner-a3f8 in 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/cache still 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