BYOC Runners on GCP for GitHub Actions
Run GitHub Actions runners as Compute Engine VMs in your own GCP project. Stack layout, service account roles, quotas, and the $0.002 per minute fee.
Last verified:
WarpBuild BYOC runs your GitHub Actions runners as Compute Engine instances inside your own GCP project, so job workspaces, caches, and workflow artifacts sit in infrastructure your organization owns and Google bills the compute to your billing account. BYOC runs on AWS, GCP, and Azure, and on GCP the WarpBuild fee is $0.002 per minute per Linux runner while the workflow itself changes by one runs-on label.
This page covers the GCP shape of BYOC: what WarpBuild creates in your project, which service account and roles the connect flow needs, the quotas to raise before your first busy day, the disk and instance settings that matter, and the split of operational responsibility between your team and WarpBuild. The click path and screenshots live in the GCP BYOC documentation.
Architecture
A GCP BYOC deployment has two halves.
The WarpBuild control plane runs outside your project. It stores runner configurations, receives the job event when a workflow queues a job carrying one of your runner labels, matches that label to a configuration, and issues the Compute Engine calls that create and terminate instances. It also serves the dashboard, the reports, and the API.
Your GCP project holds every resource that touches your code: the Compute Engine instances that execute jobs, the VPC and subnetworks those instances boot into, and the Cloud Storage bucket that backs caches, container image layer caches, logs, and other workflow artifacts. Every resource in that list is created inside the project you connect.
Three objects join the halves, and they are created in this order.
The cloud connection. Connecting a GCP project creates a service account in that project carrying the permissions WarpBuild needs to build stacks and manage runners. WarpBuild's own service account impersonates it to generate short lived tokens, which is why the IAM Service Account Credentials API has to be enabled before you start. Deleting the connection removes that access path, and WarpBuild blocks the delete while stacks still depend on it.
The stack. A stack is the set of infrastructure components in one region of your project that runners need: the VPC, one public and one private subnetwork, and the Cloud Storage bucket. Stacks are built through Cloud Deployment Manager V2, which is the second API you enable, and the dashboard shows a pending state while Deployment Manager works.
The custom runner. A runner configuration names the stack it belongs to, one or more Compute Engine machine types in priority order, the disk type and size, whether instances are spot, whether they get static IPs, and optionally a service account to attach to each instance. The dashboard assigns a Runner ID prefixed with warp-custom-, and that ID is the label you put in runs-on.
Region and bucket are fixed at creation
Three stack properties cannot be changed after the stack exists: the stack name, the Cloud Storage bucket, and the region. Treat the create form as a one-way decision. Picking a different region later means creating a second stack, creating runner configurations against it, and moving runs-on labels over, which is cheap in workflow terms and slow in review terms.
The bucket name has to be globally unique across Cloud Storage. A name already taken in another organization fails the Deployment Manager create with a 403 on storage.buckets.get, and the error text names the Google-managed cloudservices.gserviceaccount.com principal rather than the name collision, which sends people looking for a permissions problem that does not exist. Prefix the bucket with something unique to your company on the first attempt.
Name stacks after the product and region so the resources stay legible in the GCP console months later. One stack per region is the normal shape: a stack does not span regions, and each additional region is another stack, another bucket, and another quota conversation with Google.
The import flow is AWS only
BYOC GCP creates its resources through the easy create flow, which builds the VPC and subnetworks according to the layout WarpBuild ships. Importing an existing VPC is supported on BYOC runners on AWS for GitHub Actions and is not available on GCP today. If a policy requires runners inside a specific pre-existing VPC, that constraint decides the cloud.
Where this sits next to hosted runners
WarpBuild-hosted runners run in US and EU regions, and the region-specific infrastructure options cover the hosted side of the placement question. With BYOC on GCP, placement is whatever region of your own project you create the stack in, and the compliance conversation moves inside your existing cloud footprint. Teams with an EU requirement usually read EU data residency for GitHub Actions runners alongside this page.
Permissions and Access
Three things have to be true in the project before the connect flow succeeds: a billing account is linked, six APIs are enabled, and the human running the flow holds enough IAM to create the resources.
APIs to enable
| API | Why WarpBuild needs it |
|---|---|
| Cloud Storage API | Caches, container image layer caches, and telemetry storage |
| IAM Service Account Credentials API | Short lived tokens minted through impersonation of the connection service account |
| Identity and Access Management (IAM) API | Creates the service account used for access management in your project |
| Cloud Deployment Manager V2 API | Creates the cloud integration and the stack as versioned deployments |
| Compute Engine API | Runner instance lifecycle |
| Cloud Resource Manager API | Resource tagging and management |
Enable each one against the project you plan to connect. The project dropdown in the GCP console is the usual source of a failed connect: the API gets enabled on a different project than the one being connected.
Roles for the person running the connect flow
The user who creates the cloud integration and the stack needs four predefined roles: Security Admin, Storage Admin, Deployment Manager Editor, and Compute Admin. Security Admin is what allows the flow to create and bind the service account, Deployment Manager Editor is what allows the stack deployment, and the other two cover the bucket and the compute resources. These roles apply to the person running setup. Runner instances carry only the service account you attach to them, covered below.
The service account attached to your runners
Runner instances can carry a service account of your choosing, which is how a job authenticates to Artifact Registry, Cloud Storage, or any other Google API without a long-lived key in a GitHub secret. The service account setup guide walks through it. The shape is a service account you create, a binding that lets WarpBuild's creator service account pass it, and whatever project-level roles the workload actually needs:
gcloud config set project "${PROJECT_ID}"
gcloud iam service-accounts create instance-sa \
--display-name="Instance Service Account"
export SA_EMAIL="instance-sa@${PROJECT_ID}.iam.gserviceaccount.com"
# CREATOR_SA is the runner-creating service account shown on the BYOC page
gcloud iam service-accounts add-iam-policy-binding "${SA_EMAIL}" \
--member="serviceAccount:${CREATOR_SA}" \
--role="roles/iam.serviceAccountUser"
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
--member="serviceAccount:${SA_EMAIL}" \
--role="roles/artifactregistry.admin"Select the service account in the Service Account field on the runner edit page. To confirm it took effect, open Compute Engine in the GCP console, pick a running runner instance, and check Service account under API and identity management. Grant this account the narrowest roles the jobs need; roles/artifactregistry.admin above is an example, and a reader role is enough for pipelines that only pull images.
Quotas, per stack, in the stack region
Quota exhaustion looks like queued jobs with no logs, so raise these before a busy day rather than during one. Assume $CON concurrently running jobs, for example 1000.
| Resource | Additional quota per stack | Notes |
|---|---|---|
| CPU | $CON times vCPU per job | Adjust for machine type and for preemptible against on-demand instances |
| Persistent Disks | $CON times DISK_TB | With Hyperdisk types, also raise provisioned IOPS and throughput quotas |
| In-use regional external IPv4 addresses | 3 plus $CON | One static IP for Cloud NAT per stack, one per concurrently running job |
| Cloud Storage | 1 | One bucket for artifact cache, container layer caches, and telemetry |
| Cloud NAT | 3 | One per stack |
| Networks | 1 | One VPC |
| Subnetworks | 2 | One public and one private subnetwork per stack |
Every one of these is regional. Change the region selector in the GCP console quota page to the stack region before editing, or the increase lands somewhere the runners never boot.
Configuration
Point a workflow at the runner
The Runner ID from the custom runners page is the label. A mixed workflow keeps Linux jobs on the GCP fleet and sends the jobs GCP BYOC does not serve to WarpBuild-hosted runners in the same file:
name: ci
on:
push:
branches: [main]
pull_request:
jobs:
unit-tests:
runs-on: warp-custom-gcp-use-linux-8x
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm test
integration-tests:
runs-on: warp-custom-gcp-use-linux-16x
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
ports: ["5432:5432"]
steps:
- uses: actions/checkout@v4
- run: ./scripts/integration-tests.sh
arm-image:
runs-on: warp-ubuntu-latest-arm64-4x
steps:
- uses: actions/checkout@v4
- run: docker build --platform linux/arm64 -t app:arm64 .
ios-build:
runs-on: warp-macos-15-arm64-6x
steps:
- uses: actions/checkout@v4
- run: xcodebuild -scheme App -destination 'generic/platform=iOS' buildThe two warp-custom- labels are runner configurations in your GCP stack. warp-ubuntu-latest-arm64-4x and warp-macos-15-arm64-6x are hosted labels from the cloud runner catalog. Mixing them in one workflow is normal: the label decides where the job lands, and nothing else in the file changes.
Instance types and spot
Give each runner configuration more than one machine type, listed in priority order. WarpBuild picks by availability, so a capacity shortfall on the first type falls through to the second instead of leaving the job queued. Keep the types close in size and price, otherwise job duration swings depending on which type won that morning.
Spot instances suit short, interruptible jobs and are priced by Google against on-demand rates published on the Compute Engine pricing page. Fallback types matter more on spot than on-demand, since spot capacity moves.
Disks
The minimum disk size is 100GB and the recommended starting point is 150GB. Disk type is the setting most worth attention on I/O-heavy pipelines:
| Disk type | IOPS | Throughput | Notes |
|---|---|---|---|
pd-balanced | Managed by GCP | Managed by GCP | Default. Balance of price and performance |
pd-ssd | Managed by GCP | Managed by GCP | Higher baseline than pd-balanced |
pd-standard | Managed by GCP | Managed by GCP | Lowest cost, for jobs that are not I/O bound |
hyperdisk-balanced | 3,000 to 160,000 | 140 to 2,400 MiB/s | Provisioned IOPS and throughput |
hyperdisk-extreme | 300 to 350,000 | Not applicable | Provisioned IOPS only |
For pd-* types, GCP scales IOPS and throughput with disk size. For hyperdisk-* types, you set provisioned IOPS, and throughput on hyperdisk-balanced, in the runner creation form. A reasonable starting configuration for large builds, container image operations, and heavy test suites is hyperdisk-balanced at 3000 IOPS and 140 MiB/s, then raise it against what the job reports.
Hyperdisk carries its own quotas. Provisioned IOPS and provisioned throughput are separate quota lines from disk capacity, and both are regional, so raise them in the stack region before switching a fleet to hyperdisk-balanced. Google documents the limits under Hyperdisk quotas. A runner configuration that asks for more provisioned IOPS than the region grants fails at instance creation, which surfaces as jobs that never start.
Instance types with bundled local SSDs, such as the c3-standard-88-lssd and c4a-standard-4-lssd families, are handled automatically on Linux images. One local SSD is formatted and mounted at the work directory during boot, several are combined into a RAID-0 array first. No setting controls it; the runner detects the NVMe devices at boot.
Networking
Static IPs place runner instances in private subnetworks behind Cloud NAT, which is what an allowlist on a third-party service usually requires. Google bills the data processing and transfer that path adds, so turn it on for the runner configurations that need a stable egress address and leave the rest on public subnetworks, where GitHub Actions traffic patterns keep transfer charges small.
Egress costs during deploy-heavy jobs are handled on the enterprise tier; see zero egress on the WarpBuild enterprise tier.
What GCP BYOC does not do
Nested virtualization turns on automatically when every machine type in a runner configuration supports it, so Android emulator jobs and similar workloads need no extra flag. Two limits are worth knowing before you plan a migration:
- Snapshot runners are not available on BYOC GCP. Workflows that depend on snapshots keep those jobs on WarpBuild-hosted runners.
- Windows BYOC runners are available on AWS and on BYOC runners on Azure for GitHub Actions. On GCP, Windows jobs stay on hosted
warp-windows-labels, as in the mixed workflow above. macOS is hosted only on every cloud.
These are the hosted labels a GCP BYOC fleet usually keeps alongside it, with the rate WarpBuild bills for each:
| Hosted label | OS | vCPU and RAM | Storage | Per minute |
|---|---|---|---|---|
warp-macos-26-arm64-6x | macOS 26 | 6 vCPU, 22 GB | 120GB SSD | $0.08 |
warp-macos-15-arm64-6x | macOS 15 | 6 vCPU, 22 GB | 120GB SSD | $0.08 |
warp-macos-15-arm64-12x | macOS 15 | 12 vCPU, 44 GB | 270GB SSD | $0.16 |
warp-windows-latest-x64-4x | Windows Server 2022 | 4 vCPU, 16 GB | 256GB SSD | $0.016 |
warp-windows-2025-x64-8x | Windows Server 2025 | 8 vCPU, 32 GB | 256GB SSD | $0.032 |
warp-ubuntu-latest-arm64-4x | Ubuntu 24.04 | 4 vCPU, 16 GB | 150GB SSD | $0.006 |
Who Manages What
BYOC splits the work along a clean line: you own the cloud account and everything Google bills, WarpBuild owns the runner lifecycle and everything above it.
| Area | Your GCP project | WarpBuild |
|---|---|---|
| Billing account | Linked by you, pays Google for compute, disk, network, and bucket storage | Bills $0.002 per minute per Linux BYOC runner |
| Quotas | Raised by you in the stack region | Documents the required quotas per stack |
| VPC, subnetworks, Cloud NAT | Created in your project, owned by you afterwards | Defines the layout and applies it through Deployment Manager |
| Cloud Storage bucket | Lives in your project, holds caches and artifacts | Reads and writes through the connection service account |
| Runner instances | Capacity, quota, and machine type availability | Creates and terminates one instance per job |
| Runner images | Optional custom base images you supply | Maintains and updates the default images |
| Runner agent and GitHub registration | Nothing to run | Installs, registers, and deregisters the agent |
| Job routing | You set runs-on to the Runner ID | Matches the label to a runner configuration |
| Runner service account | You create it and grant roles | Passes it to the instances |
| Stack and connection updates | You apply them when prompted | Ships them as pending updates |
| Support and compliance | Your project controls and audits | SOC 2 Type 2, plus Slack support channels on demand |
What each side charges
On BYOC the per-minute fee covers the platform and the add-ons come with it:
| Line item | Rate | Billed by |
|---|---|---|
| Linux BYOC runners | $0.002 per minute | WarpBuild |
| Windows BYOC runners (AWS and Azure) | $0.002 per minute | WarpBuild |
| BYOC add-ons, including cache | Included | WarpBuild |
| Compute Engine instances | Your machine type rate | |
| Persistent Disk or Hyperdisk | Your disk and provisioned IOPS rates | |
| Cloud Storage bucket and Cloud NAT | Your storage and transfer rates |
The WarpBuild pricing page carries the full rate card for both models.
A worked model at 300,000 Linux minutes a month
Take a team running 300,000 minutes a month of Linux jobs on a 4 vCPU, 16 GB class machine. GitHub list prices below come from the GitHub Actions billing reference and the GitHub pricing page, checked on 2026-08-13.
| Option | Rate per minute | Monthly, 300,000 minutes | Cloud compute |
|---|---|---|---|
| GitHub-hosted 4-core Linux larger runner | $0.012 | $3,600 | Included |
WarpBuild hosted warp-ubuntu-latest-x64-4x | $0.008 | $2,400 | Included |
| WarpBuild BYOC on GCP, Linux | $0.002 | $600 in WarpBuild fees | Billed by Google to your project |
The middle row is a like-for-like list price comparison: warp-ubuntu-latest-x64-4x (4 vCPU, 16 GB) costs $0.008 per minute against $0.012 per minute for the 4-core Linux larger runner (4 vCPU, 16 GB), a 33 percent lower list price. At 8 vCPU the same arithmetic gives $0.016 against $0.022, a 27 percent lower list price. Both GitHub list prices were checked on 2026-08-13.
The third row is a different kind of number and needs care. The $600 is the WarpBuild fee only. Your total on BYOC is that fee plus what Google charges for the instances, the disks, the bucket, and the network, at whatever rates your project pays after committed use discounts and spot. Price the machine type you actually plan to run on Google's Compute Engine pricing and add it to the $600 before comparing rows. Teams with committed use discounts already in place, or with a large spot appetite, are the ones for whom BYOC usually lands lowest.
Google publishes machine and Spot VM rates on the Compute Engine pricing page. Use those rates with your measured job duration before estimating a GCP fleet's total.
Two other BYOC effects belong in the model. Cache add-ons are included in the BYOC fee, and the cache itself sits in your own Cloud Storage bucket, so cache storage moves from a WarpBuild line item to a Google one. And spot instances are configurable per runner, so a fleet split between on-demand instances for merge-queue jobs and spot for pull request jobs changes the Google side of the bill without touching workflow files.
Automation and rollout
Terraform support exists for BYOC on AWS; on GCP, the connection and the stack are created from the dashboard, then managed through the API.
A rollout that works: connect the project, create one stack in the region your team already uses, create a single runner configuration at 8 vCPU, and move one noisy repository to it. Watch queue time and job duration for a week in the reports, raise quotas against what you observed, then move the rest of the Linux fleet. Keep macOS and Windows jobs on hosted labels the whole way through.
FAQ
Does WarpBuild hold standing credentials in my GCP project?
The cloud connection creates a service account in your project. WarpBuild's service account impersonates it to generate short lived tokens, so access is scoped to that service account and ends when you delete the connection.
Can I run macOS or Windows jobs on GCP BYOC?
GCP BYOC runners are Linux Compute Engine instances. MacOS and Windows jobs keep a hosted warp- label in the same workflow. Windows BYOC runners are available on AWS and Azure.
Which GCP quotas do I need to raise before the first busy day?
In the stack region, raise CPU, persistent disk, in-use regional external IPv4 addresses, Cloud NAT, networks, and subnetworks. With Hyperdisk volumes, also raise the provisioned IOPS and throughput quotas in that region.
Can I create a GCP stack with Terraform?
Terraform support exists for BYOC on AWS. GCP stacks are created from the WarpBuild dashboard.
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.