Spot pricing
How RunsOn launches runners on EC2 Spot capacity, and when to opt out.
What are spot instances?#
Spot instances are a purchasing option that allows you to take advantage of unused EC2 capacity in the AWS cloud.
This can result in significant cost savings, often up to 90% off the on-demand price.
However, spot instances are not guaranteed to be available at all times and can be terminated by AWS if the capacity is needed for on-demand instances.
Usage#
Flex#
In Flex, disable Spot per job with spot=false:
jobs: ci: runs-on: runs-on=${{ github.run_id }}/runner=2cpu-linux-x64 deploy: runs-on: runs-on=${{ github.run_id }}/runner=2cpu-linux-x64/spot=falseTest Flex interruption handling against a running Spot job with the CLI:
AWS_PROFILE=runs-on-admin roc interrupt "$JOB_URL" --waitFleet#
In Fleet, spot behavior belongs in the Terraform-owned runner fleet definition. Publish a separate on-demand runner fleet for workflows that cannot tolerate interruption, and target it from workflows via its fleet label. See Fleet installation guide for the supported Terraform inputs.
Default behavior#
RunsOn always tries Spot first and falls back to on-demand if Spot capacity is unavailable. The penalty is a 2–3s launch delay on fallback.
Spot interruption is also rare for short jobs: AWS does not bill any Spot instance interrupted within its first hour, and the request is rejected up front if capacity is critical. That makes Spot a safe default for almost all CI work under one hour without critical side effects. See AWS billing for interrupted Spot instances for the exact rules.
Disable Spot when:
- the workflow cannot be interrupted (deployment, migration, release signing, long-running jobs with poor checkpointing);
- you pin a specific instance type that often hits capacity ceilings and want to skip the Spot retry delay.
Spot allocation strategies#
Supported allocation strategies on RunsOn include:
spot=price-capacity-optimizedorspot=pco: This strategy balances between price and capacity to optimize cost while minimizing the risk of interruption.spot=lowest-priceorspot=lp: This strategy focuses on obtaining the lowest possible price, which may increase the risk of interruption.spot=capacity-optimizedorspot=co: This strategy prioritizes the allocation of instances from the pools with the most available capacity, reducing the likelihood of interruption.
For more details on each strategy, refer to the official AWS documentation on Spot Instance allocation strategies ↗. For guidance on which strategy to pick when trading cost against stability, see Cost control.
Automatic Spot protection and recovery#
On Flex, RunsOn will automatically force spot to false in the following conditions:
- anytime the job is retried (i.e. run attempt > 1);
- whenever the spot instance quota is exhausted — Flex falls back to on-demand for the next 5 minutes and emits an email alert so you can request an EC2 spot quota increase;
- if the spot circuit breaker (available since v2.6.7) is active, in which case Flex falls back to on-demand for the recovery duration configured on the circuit breaker.
The spot circuit breaker trips to on-demand once spot interruptions exceed a threshold within a time window. Its value uses the format COUNT/WINDOW_MINUTES/RECOVERY_MINUTES:
COUNT: number of interruptions before the breaker trips;WINDOW_MINUTES: time window, in minutes, over which interruptions are counted;RECOVERY_MINUTES: time, in minutes, before spot is tried again.
Raising COUNT makes the breaker less sensitive, tolerating more interruptions before switching to on-demand.
Fleet uses the same circuit-breaker format and default: spot_circuit_breaker = "2/15/30"; set it to false to disable it. It tracks interruption notices across Fleet targets and sends new launches to on-demand capacity for the recovery period after the threshold is reached.
Fleet also recovers a first-attempt workflow run when the instance that ran its job was interrupted and the run finishes unsuccessfully. It starts GitHub’s rerun failed jobs flow after first placing that Fleet target on on-demand capacity. This requires Actions read and write on the Fleet GitHub credential. For a GitHub App, grant Actions Read and write; an enterprise PAT also needs repo in addition to manage_runners:enterprise.
Set retry: false on a Fleet runner to opt that runner out of creating recovery markers and initiating the rerun. It does not prevent a person or another system from rerunning the workflow, and it does not disable interruption tracking for the circuit breaker. Use a separate on-demand runner fleet when a workload must never start on Spot.
Flex vs Fleet#
Same Spot-first default; the difference is where the override lives.
| Aspect | Flex | Fleet |
|---|---|---|
| Default behavior | Spot first, on-demand fallback | Spot first, on-demand fallback |
| Disable per job | spot=false workflow label | — (workflow can’t override the fleet) |
| Disable per fleet | n/a | Configured in the Terraform runner fleet |
| Allocation strategy | spot=pco / lp / co label | Configured in the Terraform runner fleet |
| Retry after an interrupted first attempt | ✓ (on-demand retry) | ✓ (reruns failed jobs on on-demand; requires Actions read/write) |
| Auto-disable on quota | ✓ | Use the Fleet circuit breaker or an on-demand runner fleet |
| Spot circuit breaker | ✓ | ✓ (2/15/30 by default; set false to disable) |
| Retry opt-out | retry=false workflow label | retry: false in the Terraform-owned runner definition |