# GitLab CI jobs on AWS spot machines

Jobs on your own runners use no compute minutes. Here is what that saves, how GitLab's own autoscaler does it, and a way with nothing to keep running.

October 9, 2026, by Supercorp.

A job on GitLab.com's own runners is paid for in compute minutes. A job on a runner of yours is not. GitLab's pricing page: "Execution on your own runners will not use your compute minutes and is unlimited." This post compares the two, looks at GitLab's own way to start machines for jobs on AWS, and shows a shorter one.

## What a minute costs

On GitLab.com a job uses compute minutes at a rate set by [the size of its runner](https://docs.gitlab.com/ci/pipelines/compute_minutes/): one for each minute on the small one (2 CPUs), two on the medium (4 CPUs), three on the large (8 CPUs). The large one is for Premium and Ultimate only. More minutes are [$10 for 1,000](https://about.gitlab.com/pricing/).

| CPUs | GitLab.com, a minute | AWS spot, a minute | The spot machine |
| --- | --- | --- | --- |
| 4 | $0.02 | $0.0012 | c8a.xlarge |
| 8 | $0.03 | $0.0028 | m8a.2xlarge |

The GitLab column is our arithmetic from those two figures, for minutes bought beyond what a plan includes. The AWS column is the spot price in us-east-1 on 8 October 2026; a disk and a public address add about $0.0002 a minute.

## What you give up

AWS can take a spot machine back with two minutes' notice, and the job on it fails. GitLab's older guide for runners on AWS says as much: "Running CI jobs on Spot instances may increase the failure rates because of the Spot instances pricing model." So whatever starts the machines should run a lost job again, somewhere it will not be lost twice.

## GitLab's own way

GitLab Runner can start machines itself. The way it recommends today is the [Docker Autoscaler executor](https://docs.gitlab.com/runner/executors/docker_autoscaler/) with its AWS plugin. The older way, the Docker Machine executor, "was deprecated in GitLab 17.5 and is scheduled for removal in GitLab 20.0 (May 2027)".

With the autoscaler you keep a *runner manager* running. [GitLab's words](https://docs.gitlab.com/runner/runner_autoscale/):

> The runner manager is a type of runner that creates multiple runners for autoscaling. It continuously polls GitLab for jobs and interacts with the public cloud infrastructure to create a new instance to execute jobs.

That manager is a machine of its own, and it "must not be a spot instance". GitLab suggests at least two, so that one can fail. You also prepare a machine image with Docker on it, an Auto Scaling group with its scaling policy set to none, and an IAM policy. To give each job a machine of its own, you set the group's capacity and use count to 1.

It works, and it is GitLab's own. It is also one or two machines that never stop, and a fair amount to set up and keep.

## With SuperCI

SuperCI has no manager to keep running. A small control plane in your account, a function, hears from GitLab when a job is queued and starts a machine for it. One command opens the dashboard:

```sh
npx @superci/cli dashboard
```

1. Sign in with AWS and let the dashboard deploy the control plane.
2. Under Repositories, choose GitLab. Create an access token with the scopes the dialog names and paste it in. A project or group token is enough.
3. Turn on the projects whose jobs should run on SuperCI.
4. Give a job the tag:

```yaml
test:
  tags: [superci]
  script:
    - npm test
```

The job runs in Docker with the image it names, as on GitLab's own runners, on a spot machine with 4 CPUs that is gone when the job ends. `tags: [superci-8cpu]` asks for a larger one.

When AWS takes a machine back, SuperCI runs the job again, by default on a machine at the full price. It works with GitLab.com and with a GitLab you host. The [GitLab CI guide](/docs/gitlab) has the details, and [Spot machines](/docs/spot-machines) what happens when one is taken back.

## Where it does not fit

GitLab jobs run in Docker, so on SuperCI they run on AWS and in Cloudflare containers, and not on Windows. A fork's merge-request pipelines run in the fork's own project, so they never reach your runners.
