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

APIWhy WarpBuild needs it
Cloud Storage APICaches, container image layer caches, and telemetry storage
IAM Service Account Credentials APIShort lived tokens minted through impersonation of the connection service account
Identity and Access Management (IAM) APICreates the service account used for access management in your project
Cloud Deployment Manager V2 APICreates the cloud integration and the stack as versioned deployments
Compute Engine APIRunner instance lifecycle
Cloud Resource Manager APIResource 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.

ResourceAdditional quota per stackNotes
CPU$CON times vCPU per jobAdjust for machine type and for preemptible against on-demand instances
Persistent Disks$CON times DISK_TBWith Hyperdisk types, also raise provisioned IOPS and throughput quotas
In-use regional external IPv4 addresses3 plus $CONOne static IP for Cloud NAT per stack, one per concurrently running job
Cloud Storage1One bucket for artifact cache, container layer caches, and telemetry
Cloud NAT3One per stack
Networks1One VPC
Subnetworks2One 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:

.github/workflows/ci.yml
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' build

The 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 typeIOPSThroughputNotes
pd-balancedManaged by GCPManaged by GCPDefault. Balance of price and performance
pd-ssdManaged by GCPManaged by GCPHigher baseline than pd-balanced
pd-standardManaged by GCPManaged by GCPLowest cost, for jobs that are not I/O bound
hyperdisk-balanced3,000 to 160,000140 to 2,400 MiB/sProvisioned IOPS and throughput
hyperdisk-extreme300 to 350,000Not applicableProvisioned 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 labelOSvCPU and RAMStoragePer minute
warp-macos-26-arm64-6xmacOS 266 vCPU, 22 GB120GB SSD$0.08
warp-macos-15-arm64-6xmacOS 156 vCPU, 22 GB120GB SSD$0.08
warp-macos-15-arm64-12xmacOS 1512 vCPU, 44 GB270GB SSD$0.16
warp-windows-latest-x64-4xWindows Server 20224 vCPU, 16 GB256GB SSD$0.016
warp-windows-2025-x64-8xWindows Server 20258 vCPU, 32 GB256GB SSD$0.032
warp-ubuntu-latest-arm64-4xUbuntu 24.044 vCPU, 16 GB150GB 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.

AreaYour GCP projectWarpBuild
Billing accountLinked by you, pays Google for compute, disk, network, and bucket storageBills $0.002 per minute per Linux BYOC runner
QuotasRaised by you in the stack regionDocuments the required quotas per stack
VPC, subnetworks, Cloud NATCreated in your project, owned by you afterwardsDefines the layout and applies it through Deployment Manager
Cloud Storage bucketLives in your project, holds caches and artifactsReads and writes through the connection service account
Runner instancesCapacity, quota, and machine type availabilityCreates and terminates one instance per job
Runner imagesOptional custom base images you supplyMaintains and updates the default images
Runner agent and GitHub registrationNothing to runInstalls, registers, and deregisters the agent
Job routingYou set runs-on to the Runner IDMatches the label to a runner configuration
Runner service accountYou create it and grant rolesPasses it to the instances
Stack and connection updatesYou apply them when promptedShips them as pending updates
Support and complianceYour project controls and auditsSOC 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 itemRateBilled by
Linux BYOC runners$0.002 per minuteWarpBuild
Windows BYOC runners (AWS and Azure)$0.002 per minuteWarpBuild
BYOC add-ons, including cacheIncludedWarpBuild
Compute Engine instancesYour machine type rateGoogle
Persistent Disk or HyperdiskYour disk and provisioned IOPS ratesGoogle
Cloud Storage bucket and Cloud NATYour storage and transfer ratesGoogle

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.

OptionRate per minuteMonthly, 300,000 minutesCloud compute
GitHub-hosted 4-core Linux larger runner$0.012$3,600Included
WarpBuild hosted warp-ubuntu-latest-x64-4x$0.008$2,400Included
WarpBuild BYOC on GCP, Linux$0.002$600 in WarpBuild feesBilled 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.