Skip to content

Developers

Sandlayer CI

Run your GitHub Actions jobs on Sandlayer microVMs by changing one line.

4 minute read


Sandlayer CI runs your GitHub Actions jobs on Sandlayer instead of GitHub's hosted runners. Your workflow files stay the same apart from runs-on. Every job gets a fresh microVM of its own, which is destroyed when the job ends.

1. Connect GitHub

Open CI in the console and choose Connect GitHub. GitHub asks two things:

  1. Where to install the Sandlayer CI App: a GitHub organization or your personal account.
  2. Which repositories it may serve: all of them, or the ones you pick.

GitHub then asks you to authorize the App. This lets Sandlayer check that the installation really is yours before linking it to your workspace. The authorization is used once and is not kept.

You need a role that may create sandboxes in the workspace (owner, admin or member). On an organization, installing the App also needs an owner of that organization. If you are not one, GitHub sends them a request. Choose Connect GitHub again once they approve it.

To change the repositories later, use the App's Configure page on GitHub. To stop running jobs here, choose Unlink in the console, then uninstall the App on GitHub if you no longer want it there.

2. Pick a label

Change runs-on in a workflow:

jobs:
  test:
    runs-on: sandlayer-4vcpu-ubuntu-2404 # was: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: make test
LabelvCPUSystem
sandlayer-2vcpu-ubuntu-24042Ubuntu 24.04
sandlayer-4vcpu-ubuntu-24044Ubuntu 24.04
sandlayer-8vcpu-ubuntu-24048Ubuntu 24.04

Jobs that ask for any other label are left to GitHub. Your other jobs keep running where they ran before.

Docker

Docker runs inside the job's own microVM. You can use docker build, docker compose and services: containers as you would on GitHub's runners. Nothing is shared with other jobs or other customers. The image cache starts empty for every job.

What a job gets

  • Isolation: a microVM of its own with its own kernel and an encrypted disk, destroyed when the job ends. Code from a pull request gets the same isolation as any other job.
  • Tools: git, Docker and the common build tools. Use the setup-* actions (actions/setup-node, actions/setup-python, actions/setup-go, …) for a specific language version.
  • Internet: jobs reach the internet. Mail ports are blocked.
  • Length: a job may run for up to 6 hours.

Watching jobs

CI in the console lists your jobs, newest first. For each one it shows:

  • its repository, workflow, label and status;
  • how long it waited for a runner (Queue) and how long it ran (Duration);
  • GitHub's conclusion;
  • a link to the run on GitHub, and to the sandbox the job ran in.

The list refreshes itself while a job waits or runs.

Concurrency sets how many jobs may run at once, from 1 to 32. Jobs past it wait in Sandlayer's queue and start as others finish.

Your plan applies to CI too:

  • a runner counts toward the sandboxes your plan lets you run at once, together with your other sandboxes; a job waits while you are at that limit;
  • a label with more vCPUs than your plan allows a sandbox fails at once, and the job list says why;
  • runners need internet access, so a plan without it runs no jobs;
  • while your workspace is suspended, jobs wait.

A runner's memory (2 GiB per vCPU), disk (14 GiB) and lifetime (GitHub's 6 hours) follow its label, not your plan's sandbox sizes.

Billing

A CI job is billed as sandbox usage: per vCPU and GiB of memory, by the minute, while its sandbox runs. It comes from the same wallet as your other sandboxes, so your plan's included usage covers it first. Waiting in the queue is not billed. Billing → Prices shows the current rates.

If the workspace runs out of money, its sandboxes stop, CI jobs included.

Did this miss something? Tell us.