Can GitHub Actions Run Windows Builds?

Yes. GitHub Actions runs Windows builds on x86-64 Windows runners. Point runs-on at a label such as warp-windows-latest-x64-8x, billed at $0.032 per minute.

Last verified:

Yes. GitHub Actions runs Windows builds on x86-64 Windows runners, and moving a job onto one is a single line change to runs-on: point it at a Windows label such as warp-windows-latest-x64-8x and the steps execute on a Windows Server machine with MSBuild, Visual Studio, and the rest of the standard Windows toolchain already installed. WarpBuild provides Linux x64, Linux ARM64, macOS, and Windows runners, and the Windows line runs from 4 vCPU at $0.016 per minute to 32 vCPU at $0.128 per minute (WarpBuild cloud runners, checked on 2026-08-13).

Answer

Windows is a supported GitHub Actions platform, and there are three ways to get a Windows machine under a job.

GitHub-hosted Windows runners. GitHub publishes windows-latest and dated labels such as windows-2022, plus a set of larger Windows runners at 4, 8, 16, and 32 cores. Private-repository minutes bill per minute, and the rates live in the GitHub Actions billing reference.

Self-hosted Windows machines. The runner agent ships a win-x64 release on github.com/actions/runner, so any Windows box you own can register against a repository or organization and advertise labels. You own the image, the patching, the Visual Studio licensing, and the scaling.

Managed Windows runners. A provider registers ephemeral Windows virtual machines against your organization and you select them by label. WarpBuild runs this shape: twelve Windows labels across Windows Server 2022, Windows Server 2025, and a Windows Server 2025 image carrying Visual Studio 2026, listed in the Windows runner catalog.

The workflow file barely moves. The Windows x86-64 runner images carry the same tooling as GitHub-hosted runners (cloud runners documentation), so the label is the change:

name: windows-build

on:
  push:
    branches: [main]
  pull_request:

jobs:
  build:
    runs-on: warp-windows-latest-x64-8x
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: "9.0.x"

      - name: Cache NuGet packages
        uses: actions/cache@v4
        with:
          path: ~\.nuget\packages
          key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.lock.json') }}
          restore-keys: |
            nuget-${{ runner.os }}-

      - name: Restore
        run: dotnet restore --locked-mode

      - name: Build
        run: dotnet build --configuration Release --no-restore

      - name: Test
        run: dotnet test --configuration Release --no-build --logger trx

      - uses: actions/upload-artifact@v4
        with:
          name: test-results
          path: "**/TestResults/*.trx"

The default shell on a Windows runner is PowerShell, runner.os evaluates to Windows, and the checkout, setup, cache, and artifact actions behave the way they do on Linux.

Detail

The Windows catalog

Twelve labels, three image families, four machine shapes. Every row below comes from the cloud runners documentation, checked on 2026-08-13.

Runner labelImagevCPUMemoryStoragePer minuteAlias
warp-windows-latest-x64-4xWindows Server 2022416GB256GB SSD$0.016warp-windows-2022-x64-4x
warp-windows-latest-x64-8xWindows Server 2022832GB256GB SSD$0.032warp-windows-2022-x64-8x
warp-windows-latest-x64-16xWindows Server 20221664GB256GB SSD$0.064warp-windows-2022-x64-16x
warp-windows-latest-x64-32xWindows Server 202232128GB256GB SSD$0.128warp-windows-2022-x64-32x
warp-windows-2025-x64-4xWindows Server 2025416GB256GB SSD$0.016none
warp-windows-2025-x64-8xWindows Server 2025832GB256GB SSD$0.032none
warp-windows-2025-x64-16xWindows Server 20251664GB256GB SSD$0.064none
warp-windows-2025-x64-32xWindows Server 202532128GB256GB SSD$0.128none
warp-windows-2025-vs2026-x64-4xWindows Server 2025 with Visual Studio 2026416GB256GB SSD$0.016none
warp-windows-2025-vs2026-x64-8xWindows Server 2025 with Visual Studio 2026832GB256GB SSD$0.032none
warp-windows-2025-vs2026-x64-16xWindows Server 2025 with Visual Studio 20261664GB256GB SSD$0.064none
warp-windows-2025-vs2026-x64-32xWindows Server 2025 with Visual Studio 202632128GB256GB SSD$0.128none

Three properties hold across the whole Windows range. Memory scales at 4GB per vCPU. Storage is fixed at 256GB of SSD on every size rather than growing with the shape, which matters for solutions that check out a large repository and then fill obj and bin directories per project. Storage is also ephemeral and is deleted when the runner terminates, so anything worth keeping goes to an artifact, a cache, or a package feed.

The vs2026 labels are transitional. They carry Visual Studio 2026 while the other Windows Server 2025 labels carry Visual Studio 2022, and Visual Studio 2026 may become the default for the Windows Server 2025 runners in a later update (cloud runners documentation). Pin the explicit label while a migration is in progress, and read the Visual Studio images page before moving a solution that depends on a specific toolset version.

A matrix is the honest way to test an image move, because the compiler toolset changes underneath the same source tree:

name: windows-image-matrix

on:
  pull_request:

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        image:
          - warp-windows-latest-x64-8x
          - warp-windows-2025-x64-8x
          - warp-windows-2025-vs2026-x64-8x
    runs-on: ${{ matrix.image }}
    steps:
      - uses: actions/checkout@v4

      - name: Record the image and toolset
        run: |
          [System.Environment]::OSVersion.Version
          & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property catalog_productDisplayVersion

      - name: Build the solution
        run: msbuild MySolution.sln /p:Configuration=Release /m

      - name: Run the test projects
        run: dotnet test --configuration Release --no-build

fail-fast: false keeps the passing legs running while you work through breakage on one image, and the vswhere step writes the toolset version into the log so a later regression can be traced to an image change rather than a code change.

What a Windows minute costs

Every WarpBuild rate below comes from the cloud runners documentation. Every GitHub rate comes from the GitHub Actions billing reference and the shapes from the GitHub-hosted runner reference, checked on 2026-08-13.

WarpBuild Windows labelShapeWarpBuild per minuteGitHub-hosted equivalentGitHub per minuteList price difference
warp-windows-latest-x64-4x4 vCPU, 16 GB$0.0164-core Windows larger runner$0.02227 percent lower list price
warp-windows-latest-x64-8x8 vCPU, 32 GB$0.0328-core Windows larger runner$0.04224 percent lower list price
warp-windows-latest-x64-16x16 vCPU, 64 GB$0.06416-core Windows larger runner$0.08222 percent lower list price
warp-windows-latest-x64-32x32 vCPU, 128 GB$0.12832-core Windows larger runner$0.16221 percent lower list price

Worked model: one .NET service repository. A team merges enough pull requests to queue 1,500 Windows jobs a month, each running 9 minutes. That is 13,500 Windows minutes.

ShapeWarpBuild per monthGitHub-hosted per monthMonthly differenceTwelve month difference
4 vCPU13,500 x $0.016 = $216.0013,500 x $0.022 = $297.00$81.00$972.00
8 vCPU13,500 x $0.032 = $432.0013,500 x $0.042 = $567.00$135.00$1,620.00
16 vCPU13,500 x $0.064 = $864.0013,500 x $0.082 = $1,107.00$243.00$2,916.00
32 vCPU13,500 x $0.128 = $1,728.0013,500 x $0.162 = $2,187.00$459.00$5,508.00

Two things to read out of that table before choosing a size. The absolute gap grows with the shape, so the largest Windows jobs are where a list price difference is worth the most in dollars. And the WarpBuild rate doubles exactly with vCPU count, which means a step up pays for itself whenever the job spends more than half its wall clock on work that actually parallelizes: MSBuild with /m, dotnet test across several test projects, or a solution with many independent project graphs. A job that spends most of its time on a single-threaded restore or a serialized packaging step gains nothing from a bigger machine, so measure before you resize.

Run the same arithmetic against your own job minutes on the pricing page.

Two limits worth planning around

WarpBuild caching is unsupported on Windows runners. The caching documentation records this under its limitations: WarpBuild caching is not supported for Windows-based runners. It is enabled by default on Linux runners, so a team that swaps actions/cache@v4 for WarpBuilds/cache@v1 across a repository has to leave the Windows jobs alone. Keep actions/cache@v4 on Windows, which stores entries in GitHub's own Actions cache service, keeps working with no extra configuration, and is what the workflow above uses for the NuGet global packages folder at %UserProfile%\.nuget\packages. A matrix that spans Linux and Windows therefore runs two cache actions, selected per leg. The Windows cache answer covers the key design that survives that split.

The 2 vCPU Windows runners are gone. Windows 2 vCPU runners were removed on June 8, 2026 (cloud runners documentation). Any workflow still pinned to a 2 vCPU Windows label fails to schedule and has to move to 4 vCPU or larger, which makes warp-windows-latest-x64-4x at $0.016 per minute the smallest Windows shape available. Grep the repository for Windows labels ending in -2x before a migration, including composite actions and reusable workflows, because a reusable workflow called from ten repositories carries the stale label into all of them.

What the Windows line does not cover

ARM64 is Linux and macOS only. The Windows catalog is x86-64 across all twelve labels, so a Windows job stays on an x86-64 label with no ARM64 alternative to move to.

Snapshot runners are the other gap. They list Linux x64 and Linux ARM64 as their supported platforms (snapshot runners documentation). A Windows job can still use per-job resource metrics and logs to show where a long MSBuild step spends its time.

Everything else in a normal Windows workflow behaves the way it does on the GitHub-hosted equivalent: checkout, the setup actions, service containers, artifacts, matrix jobs, reusable workflows, and job-level concurrency, so a release day that fans out to fifty Windows jobs at once runs them the same way a five-job day does.

Which Windows image should a GitHub Actions job pick?

warp-windows-latest-x64-<size> resolves to Windows Server 2022 and is the safe default for an existing workflow. Use warp-windows-2025-x64-<size> for Windows Server 2025 with Visual Studio 2022, and warp-windows-2025-vs2026-x64-<size> when the build needs Visual Studio 2026. All three families share the same four shapes, the same 256GB SSD, and the same per-minute rates, so an image move changes the toolchain and leaves the bill alone. The Visual Studio images page lists what each image carries.

What is the smallest Windows runner available?

4 vCPU with 16GB of memory, at $0.016 per minute. The 2 vCPU Windows runners were removed on June 8, 2026, so a workflow pinned to a 2 vCPU Windows label needs to move to 4 vCPU or larger. Every shape is listed in the Windows runner catalog.

Does the WarpBuild cache work on Windows runners?

No. The caching documentation records WarpBuild caching as unsupported for Windows-based runners, and it is enabled by default on Linux runners only. On a Windows job, keep actions/cache@v4, which writes to GitHub's own Actions cache service and needs no extra configuration.

Can GitHub Actions run Windows builds on ARM64 hardware?

Not on WarpBuild. The Windows catalog is x86-64 only, from warp-windows-latest-x64-4x through warp-windows-latest-x64-32x. ARM64 runners cover Linux and macOS, so a Windows job stays on an x86-64 label.

Move a Windows job with the labels in the Windows runner catalog, check the toolchain your solution needs on the Visual Studio images page, and see the surrounding pipeline in running .NET builds on GitHub Actions. Price the change against your own Windows minutes on the pricing page.

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.