·Updated ·Mergestorm Team·Engineering
Surge public beta: on-demand CI runners that scale to zero
Surge runs your GitHub Actions jobs on shared cloud servers that start when CI needs them and shut down when it goes quiet. Each job gets its own fresh sandbox and you pay only for the minutes it runs. Minutes are included with Scale, Pro and Maelstrom plans. Here is how it works and how to set it up.

Updated October 3, 2026. Surge launched on October 1 with a separate set of servers for each repository. It now runs every job in its own sandbox on shared servers and charges only for the minutes your jobs run. This post describes Surge as it works today.
Mergestorm already reviews your pull requests (Vortex on every push), patches clear findings (Cyclone), and lands stacks through the merge queue. It also runs the CI those steps wait on. Surge is in public beta.
Surge gives a private GitHub repository on-demand, self-hosted GitHub Actions runners. The servers start when CI needs them and shut down once they sit idle. Each job runs in its own fresh sandbox, and you pay only for the minutes your jobs run. Nothing runs and no Surge minutes are counted while CI is quiet, so Surge scales to zero.
Surge minutes are included with Scale (300 per period), Pro (1,000 per credit pack) and Maelstrom (3,000 per credit pack) plans; see Billing. Surge is a public beta: capacity is limited, and your jobs fall back to GitHub-hosted runners whenever Surge cannot take them.
Why we built it
Idle runners cost money. A self-hosted runner that is always on bills around the clock, including nights, weekends, and the hours between pushes. Stopping the server does not always fix that: at many cloud providers a stopped server is still billed. The only runner that costs nothing is one that does not exist.
Running your own runners is work. Someone has to create the servers, register them with GitHub, keep one job from reading the next job's files, and delete everything that gets left behind. Most teams would rather not own that.
Surge does both jobs for you: it starts runners only while there is CI to run, and it handles registration, isolation and cleanup.
How it works
Each job you want on Surge has one line:
runs-on: ${{ vars.CI_SURGE_RUNNER || 'ubuntu-latest' }}
CI_SURGE_RUNNER is a repository variable that Mergestorm manages. Mergestorm sets it to your runner label only while a Surge runner is online, and deletes it when Surge is off. When the variable is set, the job runs on Surge. When it is unset, the expression falls back to ubuntu-latest and the job runs on a GitHub-hosted runner exactly as it did before.
That fallback is the safety net for the whole product. If Surge is off, still starting, out of minutes, or the beta has no room, your jobs run on GitHub-hosted runners as usual. Your workflow file does not change either way.
The rest happens on our side:
- Demand. In Auto mode, Surge starts runners when a workflow run you chose to watch needs them (the default is the workflow named
CI) and scales back to zero when CI goes quiet. In Manual mode, Surge stays on, gives each job a runner as it queues, and turns itself off after 30 minutes with no jobs. - A fresh sandbox per job. Each job gets a new container with its own user-space kernel (gVisor), registered with GitHub for that one job. When the job ends, the sandbox is thrown away.
- Scale to zero. When there is no more work, Mergestorm turns routing off first, lets running jobs finish, and then deletes the servers. It deletes them; it does not stop them.
A separate process on another machine sweeps for leftover servers and deletes them. The rules for when routing may be on and when a server may be deleted are written down as a TLA+ model and checked, so a runner is not pulled out from under a job that is running on it.
Set it up
You need a private repository (public and internal repositories are refused), admin access to it on GitHub, and a Scale, Pro or Maelstrom plan with an active or trialing subscription.
-
Install the app. Install the Mergestorm Surge GitHub App on the repository. Mergestorm opens the CI setup pull request through it and learns from it when CI runs.
-
Choose the repository. In Mergestorm, open Dashboard › Surge, choose the repository from the list, and choose Set up Surge. Surge is set once per account and can serve every private repository you connect.
-
Route your jobs. Under Repositories, choose Set up CI. Mergestorm opens a pull request that points each job on
ubuntu-latest,ubuntu-24.04orubuntu-22.04at the routing variable, and lists the jobs it left alone. Merge it. To do it by hand instead, changeruns-onon the jobs you want to move:jobs: test: runs-on: ${{ vars.CI_SURGE_RUNNER || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - run: npm ci - run: npm test -
Turn it on. On the Surge tab, pick Auto or Manual. Stop Surge turns everything off and lets running jobs finish.
-
Push. The next run uses Surge as soon as a runner is online. The Surge tab shows your jobs, and minutes used and left this period show there and on the Billing page.
The full reference is in the Surge docs.
What you pay
One minute of a job running on Surge is one Surge minute, counted from when the job starts until it ends and rounded up per job. Starting servers, idle time and caches cost you nothing.
- Minutes come with paid plans. Scale has 300 per credit period, Pro 1,000 per credit pack and Maelstrom 3,000 per credit pack (up to 20 packs), while the subscription is active or trialing.
- You can buy more. Extra minutes are sold on the Billing page in packs: 1,000 for $5, 5,000 for $25 and 20,000 for $100.
- You can cap it. Set a spend cap in Settings › Surge. When your minutes run out or you reach the cap, Surge pauses for an hour, or until you buy minutes or raise the cap. While it is paused, new jobs run on GitHub-hosted runners and jobs already running finish.
Isolation and security
- Shared servers, separate sandboxes. Surge servers are shared between customers. Each job runs in its own gVisor sandbox, which is created for that job and thrown away when it ends. A job cannot see other jobs or the server.
- No way in. Servers accept no inbound connections. A job cannot reach the cloud metadata service, private networks, the server, or other jobs.
- No lasting GitHub credential. A job only ever holds a single-use runner registration for its own repository.
- Caches stay with the repository. Dependency caches (npm, Yarn, pip and
~/.cache) are kept per repository and mounted only into that repository's jobs. All jobs of a repository, including pull requests, share its cache.
Beta details and limits
- Beta capacity is limited. Only so many jobs run on Surge at once across all customers. At busy times a job can wait for a runner, and when the beta has no room, Surge does not start one for you and your jobs run on GitHub-hosted runners.
- Private repositories only, and you need to be a repository admin to connect one. A repository is served by one account at a time.
- The Mergestorm Surge GitHub App is required on the repository, for the setup pull request and for Auto.
- Linux x64 runners. Jobs run as root inside their sandbox, so
sudoandapt-getwork. The runner is not a copy of GitHub'subuntu-latestimage, so install toolchains in the job with thesetup-*actions, as most workflows already do. - Docker works, with limits.
docker runanddocker buildwork on the host network, and a port mapping works when both ports match (for example-p 5432:5432). Service containers (services:) and container jobs (container:) are not supported; Set up CI leaves those jobs on GitHub-hosted runners. - Runners run in the US (Ashburn, Virginia).
What's next
These are what we are working on. They are not shipped yet.
- More capacity, so jobs wait less at busy times.
- Shorter start-up, so the first job after a quiet period waits less for its runner.
Try it
Open Dashboard › Surge, choose a private repository, and let Mergestorm open the setup pull request. Merge it, turn Surge on, push, and watch the runners come up and go back to zero. The Surge docs cover every setting.
Mergestorm now covers the whole path from a push to a merge: review, fixes, the merge queue, and the CI compute underneath them.