The BYOC Runner Lifecycle for GitHub Actions
A BYOC runner is one VM created in your cloud account when a GitHub Actions job is queued and terminated when it ends. Stages, ownership, and cost.
Overview
A BYOC runner is a single virtual machine that WarpBuild creates in your own cloud account when a GitHub Actions job is queued for its label, and terminates when that job finishes. The decision to create and destroy it belongs to the WarpBuild control plane; the machine, the disk, and every byte of build data belong to your account.
That one-job-one-VM rule is what the rest of this page unpacks: which component performs each step, what exists at each stage, and what survives termination. BYOC runs on AWS, GCP, and Azure. The stage names below use AWS vocabulary because the BYOC AWS architecture reference documents the resource graph in that form, and the sequence is the same on the other two clouds.
The full cycle, from a queued job to an empty account:
- A workflow job is queued with a
runs-onlabel matching one of your custom runners. Custom runners are addressed by Runner ID, which is the runner name prefixed withwarp-custom-. - The control plane matches the label to that runner configuration: instance types in priority order, disk size and throughput, subnet placement, optional instance profile, spot or on-demand.
- The control plane assumes the role you granted at connection time and calls your cloud API to launch the instance, either fresh or by powering on a pooled standby VM.
- The VM boots inside the stack VPC with the stack security group attached. Local NVMe volumes, where the chosen instance type has them, are detected and mounted to the work directory at boot with no configuration.
- The runner agent registers as a just-in-time runner and holds an outbound long poll. GitHub assigns the job to it.
- The job runs. Cache reads and writes and runner system logs go to the object storage bucket in your stack.
- The job completes. The control plane terminates the instance, and the encrypted volume is destroyed with it.
Architecture
The split that makes the lifecycle predictable is that scheduling authority and execution live in different places. The control plane holds no build data and runs no build step. The data plane holds every instance and never decides on its own when to create one.
| Responsibility | Owned by | Runs in |
|---|---|---|
| Watching the GitHub Actions job queue through the GitHub App connection | Control plane | WarpBuild |
Matching a runs-on label to a custom runner configuration | Control plane | WarpBuild |
| Deciding instance type, spot or on-demand, and fallback order | Control plane | WarpBuild |
| Issuing the launch call against the cloud API | Control plane, through your granted role | API call into your account |
| The instance, its encrypted volume, and the job filesystem | Data plane | Your account |
| Runner agent registration and the outbound poll to GitHub | Data plane | Your account |
| Artifact cache, container layer cache, and runner logs | Data plane | Your stack object storage bucket |
| Issuing the terminate call when the job completes | Control plane, through your granted role | API call into your account |
| Compute, storage, and data transfer charges | Data plane | Your cloud invoice |
Two consequences follow. First, a WarpBuild outage cannot leave build data stranded somewhere you cannot reach, because the data never left your account. Second, the launch authority is exactly the permission set in the connection role, so revoking that role stops new instances from being created without touching anything already running. The role and its policy blocks are covered on the AWS BYOC hub page, and the terms are defined in control plane and data plane.
Isolation is a property of the same lifecycle. Each runner runs in its own VM, created on demand and destroyed after each build, and each runner has its own encrypted storage volume with the same lifetime. VMs are ephemeral and never reused. WarpBuild does not access or store build secrets; secrets stay in your repository and reach only the runner environment. The details are in the security documentation.
What exists at each stage, and who pays for it:
| Stage | What exists in your account | What is billable |
|---|---|---|
| Job queued | Nothing new | Nothing |
| Launch call issued | A launch template and a pending instance request | Nothing yet |
| Boot and registration | One instance, one encrypted volume, one just-in-time runner registration | Instance and volume, at your cloud rates |
| Job running | The same instance, plus cache and log objects being written | Instance, volume, storage, and the WarpBuild per-minute fee |
| Termination | The instance and volume are deleted | Charges for both stop |
| After the job | Cache objects and runner logs in the stack bucket | Storage only |
Configuration
Four runner settings change the shape of the cycle. Everything else in a custom runner configuration affects what the job can do rather than how the machine comes and goes.
Fallback instance types. A runner configuration can list several instance types in priority order. When capacity for the first type is unavailable in the region, the launch call falls through to the next one, which keeps queued jobs from stalling on a single shape. Pick types with similar performance so that a fallback does not change your build times, for example m7a.xlarge and m7i.xlarge.
Spot or on-demand. Spot instances suit short, interruptible jobs. A spot instance can be reclaimed at any time, which ends that job's run, so the trade is capacity price against a retry. The instance type is chosen from availability and price across the types you listed.
Standby disks. A standby disk is a VM of the runner instance type that is booted once so that networking and machine configuration complete, then shut down without being terminated. When a job arrives, one is powered on and the job starts in about 15 seconds instead of building a machine from scratch. If the pool is empty, a fresh VM is created and the job starts at the normal provisioning time. Spot instances are not supported for standby disks. Sizing guidance is on the standby disks page.
Disk configuration. Size, throughput, and IOPS are set per runner. The documented minimum is 100 GB at 125 MBps and 3000 IOPS, with 150 GB at 400 MBps and 4000 IOPS recommended. The volume is created at boot and destroyed at termination, so this is a per-job cost rather than a standing one.
None of this reaches the workflow file. A job moves onto a BYOC runner by label alone:
name: ci
on:
pull_request:
branches: [main]
jobs:
lint:
runs-on: warp-ubuntu-latest-x64-2x
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run lint
integration:
runs-on: warp-custom-linux-x64-8x
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:integrationThe lint job runs on WarpBuild-hosted capacity and the integration job runs in your account. Both jobs get a fresh VM and both leave nothing behind, so the mixed fleet is a placement choice rather than a behavior change.
Operations
The question that decides most reviews is what remains after a job ends.
| Resource | State after the job |
|---|---|
| Runner instance | Terminated |
| Encrypted volume attached to it | Destroyed with the instance |
| Workspace, checked-out source, job environment | Destroyed with the volume |
| Just-in-time runner registration | Consumed by that one job |
| Launch template created for the job | Deleted |
| Artifact cache objects in the stack bucket | Kept until your lifecycle policy expires them, 7 days recommended |
| Runner system logs in the stack bucket | Kept under the same policy |
| Standby pool VMs | Shut down rather than terminated, and refilled by the control plane |
| Stack VPC, subnets, security group, and bucket | Unchanged, outliving every job |
| Custom runner configuration and cloud connection | Unchanged |
Both bucket prefixes grow without bound if you leave them alone, so the retention rule is the one piece of housekeeping the lifecycle asks of you. Every instance carries the warpbuild-runner-id, warpbuild-runner-labels, and warpbuild-stack-name tags, which is how you trace a line in a cost report back to the runner class that produced it, or confirm that nothing tagged managed-by: warpbuild is still running after a quiet weekend.
Tearing down runs in the reverse order of setup, and the dashboard enforces it: a stack cannot be deleted while custom runner configurations depend on it, and a cloud connection cannot be deleted while stacks depend on it. A full list of the resources involved is on what WarpBuild creates in your cloud account.
Billing follows the same boundary. WarpBuild charges $0.002 per BYOC runner minute for Linux runners and $0.002 per minute for Windows runners, measured against job time, and your cloud account bills the instance, the volume, and data transfer at your own rates. The fee does not scale with instance shape:
| Shape | WarpBuild-hosted rate per minute | WarpBuild BYOC fee per minute |
|---|---|---|
| Linux 2 vCPU, 8 GB | $0.004 | $0.002 |
| Linux 8 vCPU, 32 GB | $0.016 | $0.002 |
| Linux 32 vCPU, 128 GB | $0.064 | $0.002 |
| Windows 8 vCPU, 32 GB | $0.032 | $0.002 |
Rates come from the pricing page, checked on 2026-08-13. The BYOC fee above applies to the Linux and Windows runners you can place in your own account.
FAQ
What creates and destroys a BYOC runner instance?
The WarpBuild control plane does both, through the IAM role or service account you granted when you connected the cloud account. It watches the GitHub Actions job queue, matches the runs-on label to one of your custom runners, calls your cloud API to launch an instance in your VPC, and calls it again to terminate that instance when the job completes. The instance itself only ever exists in your account.
Does anything from my build stay behind after the runner is destroyed?
The instance and its encrypted volume are destroyed with the job, and the workspace, the checked-out source, and the job environment go with them. What persists is what you asked to persist: artifact cache objects and runner system logs in the stack object storage bucket, which the documentation recommends expiring on a 7 day lifecycle policy. WarpBuild does not access or store build secrets.
Is one instance reused for a second job?
No. Each GitHub Actions job runs on its own freshly provisioned VM that is terminated when the job finishes, so no state carries from one job to the next. A standby disk pool changes the boot path rather than that rule: a pooled VM is pre-initialized and shut down, powered on for one job, and terminated at the end of it.
Start with $10 in free credits
Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.