Windows GitHub Actions Runners on BYOC AWS

WarpBuild BYOC runs Windows Server 2022 GitHub Actions runners as EC2 instances inside your own AWS account. Architecture, documented minimums, images, cost.

Last verified:

Overview

WarpBuild BYOC runs Windows Server 2022 x86-64 GitHub Actions runners as EC2 instances inside your own AWS account, launched per job and terminated when the job finishes. You apply a CloudFormation stack, define a Windows custom runner on top of it, and point runs-on at that runner's label; WarpBuild watches the job queue and calls the AWS API with the IAM role the stack created.

WarpBuild provides Linux x64, Linux ARM64, macOS, and Windows runners. BYOC runs on AWS, GCP, and Azure, and the feature matrix marks Windows x86-64 as supported on BYOC AWS and BYOC Azure and pending on BYOC GCP, checked on 2026-08-13. The AWS BYOC page covers the stack, the IAM surface, and the Linux path; this page covers what changes when the guest is Windows.

Three things change:

  • The AWS BYOC configuration guide publishes a separate set of minimum infrastructure requirements for Windows Server 2022 x86-64 runners, and they sit above the general custom runner minimums.
  • A custom Windows AMI has requirements a Linux AMI does not, starting with aria2 on the system PATH and a sysprepped source instance.
  • WarpBuild caches are not supported for Windows based runners (cloud runners documentation, checked on 2026-08-13), so the workflow keeps actions/cache.

Architecture

The split is the same one Linux BYOC uses. WarpBuild operates the control plane that holds the GitHub App connection, the runner configuration, and the queue watch. Your AWS account holds the data plane: a VPC with public and private subnets, a security group, an S3 bucket for the artifact cache and runner logs, and the EC2 instances and EBS volumes created per job.

Each Windows job gets a fresh instance. Nothing carries over between jobs, which is why a Windows runner definition has to be sized for a cold machine rather than for a long-lived agent that keeps a warm package cache on local disk.

Three runner behaviors read differently on Windows, and the first two push work back onto the disk configuration:

BehaviorLinux BYOC runnerWindows BYOC runner
Local NVMe instance store auto-mountDetected at boot and mounted at the work directory, RAID-0 across multiple devicesNot supported; the work directory lives on EBS
WarpBuild cache actionEnabledNot supported; use actions/cache
Snapshot runnersNot supported on BYOCNot supported on BYOC or on Windows

Because the work directory sits on EBS on every Windows job, the volume settings in the runner definition are what a slow dotnet restore or a slow MSBuild link step usually traces back to.

Resource tagging is worth setting up before the first Windows runner, since it is the only way to separate Windows spend from Linux spend in AWS Cost Explorer. The stack tags every resource it creates with warpbuild-managed-by, warpbuild-github-org, warpbuild-runner-labels, warpbuild-runner-id, warpbuild-stack-id, and warpbuild-stack-name. Filtering a cost report on warpbuild-runner-labels gives per runner class spend, so a Windows label and a Linux label on the same stack report separately with no extra instrumentation.

Configuration

Bring up the stack first, following the AWS BYOC configuration guide, then create the Windows custom runner. These are the documented numbers, checked on 2026-08-13.

SettingGeneral custom runner minimumGeneral best practiceWindows Server 2022 x86-64 on AWS
Instance sizeYour instance types in priority orderTypes of similar price and performanceAt least 8 vCPU, m7a series recommended
Disk size100 GB150 GBFollows the general guidance
Disk throughput125 MBps400 MBps500 MBps
Disk IOPS300040006000

The instance row catches teams sizing from the hosted catalog. Hosted Windows runners start at 4 vCPU with 16 GB, since the 2 vCPU Windows shapes were removed on June 8, 2026, and the BYOC guidance starts a step above that at 8 vCPU. List several instance types in priority order. The workflow names one label and WarpBuild picks an available type from your list, so a capacity gap in one m7a size does not park a queued Windows job.

Two more runner-level settings apply the same way they do on Linux. Require IMDSv2 forces token-authenticated metadata requests, set on the Update Runner page or at creation time. The Instance Profile ARN field attaches AWS authority to the job itself, configured per runner, so a Windows deploy runner and a Windows test runner carry different permissions under one stack. Spot instances are supported on BYOC AWS and suit short jobs that tolerate interruption; AWS bills spot capacity in your own account at its published rates.

Custom Windows AMIs

BYOC runners can boot your own AMI, and the custom VM images guide lists what a Windows image has to carry. Linux and Windows AMIs are both supported. Four notes are specific to Windows on AWS:

  1. aria2 has to be installed and reachable through the system PATH. WarpBuild downloads job artifacts with it because the default Windows method is slow. The guide includes a PowerShell block that unpacks the release into C:\Tools\aria2 and appends that directory to the machine Path variable.
  2. The EC2 instance has to be sysprepped before you create the AMI from it, through the Amazon EC2Launch settings dialog or through the Packer sysprep commands the guide links.
  3. Jobs run under runneradmin, the same user GitHub's Windows runners use, and WarpBuild creates the account if the image lacks it. User-scoped environment variables baked into another account will not reach the job, so move them to machine scope.
  4. Pre-job and post-job hooks use the WARPBUILD_ACTIONS_RUNNER_HOOK_JOB_STARTED and WARPBUILD_ACTIONS_RUNNER_HOOK_JOB_COMPLETED variables, set at machine level from PowerShell rather than in a user profile.

One operational detail catches people the first time they debug an image: the stack does not open RDP port 3389 by default, so reaching a Windows instance interactively means adding an inbound rule for your own CIDR block. More image detail is on the custom AMIs page.

The workflow

A BYOC runner is addressed by its Runner ID, which is the runner name with the warp-custom- prefix. Hosted labels and BYOC labels coexist in one workflow file.

.github/workflows/build.yml
name: build
on:
  push:
    branches: [main]
  pull_request:

jobs:
  windows-build:
    runs-on: warp-custom-win2022-use1-8x
    steps:
      - uses: actions/checkout@v4
      - uses: actions/cache@v4
        with:
          path: ~\AppData\Local\NuGet\v3-cache
          key: nuget-${{ hashFiles('**/packages.lock.json') }}
      - run: dotnet restore
      - run: dotnet build --configuration Release --no-restore
      - run: dotnet test --configuration Release --no-build

  linux-package:
    needs: windows-build
    runs-on: warp-ubuntu-latest-x64-8x
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/package.sh

Operations

Price the three routes for the same 8 vCPU, 32 GB Windows job before you migrate. WarpBuild rates come from the pricing page; the GitHub rate comes from the GitHub Actions billing reference, checked on 2026-08-13.

RouteRate per minuteWho bills the compute
GitHub-hosted 8-core Windows larger runner$0.042GitHub
WarpBuild hosted warp-windows-latest-x64-8x$0.032WarpBuild
WarpBuild BYOC on AWS$0.002 WarpBuild feeYour AWS account

On the hosted route the arithmetic is (0.042 - 0.032) / 0.042 = 24 percent lower list price, GitHub list price checked on 2026-08-13. The BYOC row is a partial bill by design: add what AWS charges your account for the m7a instances, for the EBS volumes, and for data transfer. AWS bills provisioned IOPS and throughput above the gp3 baseline separately (AWS EBS pricing, checked on 2026-08-13), so the 6000 IOPS and 500 MBps the Windows guidance calls for cost more per volume than the 3000 IOPS floor a Linux runner can sit on. Model a real month of Windows minutes with your own instance mix.

Ownership of the image patch cycle moves with the image. WarpBuild patches WarpBuild-managed runner images. A custom Windows AMI is rebuilt on your schedule, which for most Windows fleets means a monthly rebuild that folds in the Patch Tuesday updates plus whatever Visual Studio workload versions your build pins. Automate the Packer build in a workflow and keep the AMI ID in the runner definition under change control.

CI observability streams OpenTelemetry system metrics from the runner agent and correlates them with GitHub Actions job logs, which is how you separate an undersized EBS volume from a slow test suite on a Windows job. Watch disk queue depth and throughput first, since that is where the documented Windows minimums bite.

SonarQube runs tens of thousands of GitHub Actions jobs per day on WarpBuild BYOC runners in its own AWS account, across Windows and Linux. That is the shape this page is written for: one stack, several custom runners, Windows and Linux labels sharing the same VPC, S3 bucket, and tagging scheme.

Sizes and rates for those hosted labels are on the Windows runners page, and the shorter platform answer is at does BYOC support Windows runners.

FAQ

What are the documented minimums for a Windows BYOC runner on AWS?

The AWS BYOC configuration guide recommends at least 8 vCPU with the m7a series, 6000 IOPS, and 500 MBps of disk throughput for Windows Server 2022 x86-64 runners, checked on 2026-08-13. The general custom runner minimum is 100 GB, 125 MBps, and 3000 IOPS, so a Windows runner cloned from a Linux definition normally needs its disk settings raised before the first job.

Does the WarpBuild cache work on Windows BYOC runners?

No. WarpBuild caches are not supported for Windows based runners, on hosted capacity and on BYOC. Use actions/cache in the workflow for NuGet packages, MSBuild output, and other Windows build state. The S3 bucket in your stack still holds runner system logs and telemetry.

What does a Windows BYOC runner cost?

$0.002 per runner minute in WarpBuild fees. AWS bills your own account for the EC2 instance, the EBS volume, and data transfer at your rates, and the higher IOPS and throughput the Windows guidance calls for are billed by AWS above the gp3 baseline.

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.