Do Caches Work on Windows GitHub Actions Runners?

No. WarpBuild caching is documented as unsupported on Windows runners. Windows jobs cache through actions/cache@v4 or a build-tool cache in the workspace.

Last verified:

No. WarpBuild caching is documented as unsupported for Windows-based runners, so a job on warp-windows-latest-x64-8x gets no WarpBuild cache, and the same statement appears on both the caching documentation and the cloud runners documentation, checked on 2026-08-13. Windows jobs still cache well through actions/cache@v4, which writes to GitHub's own Actions cache service and needs no extra configuration on a WarpBuild runner, or through a build-tool cache written into the job workspace.

Answer

The support boundary is short enough to state in three lines.

  • WarpBuild cache is available on Linux runners and is enabled by default there.
  • The caching documentation's limitations section records one entry: WarpBuild caching is not supported for Windows-based runners.
  • On a Windows runner, actions/cache@v4 is the cache action to use, and it works from a WarpBuild Windows runner with no extra setup.

WarpBuild provides Linux x64, Linux ARM64, macOS, and Windows runners, and the cache feature does not cover the Windows fleet. That is the accurate answer, and knowing it before you write the workflow saves a debugging session over a cache step that silently does nothing.

Here is the shape a Windows job wants. The label is a real Windows runner label from the catalog, and the cache action is the upstream one:

name: windows-build

on:
  push:
    branches: [main]
  pull_request:

env:
  NUGET_PACKAGES: C:\nuget

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

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

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

      - name: Restore
        run: dotnet restore -p:RestoreLockedMode=true

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

      - name: Test
        run: dotnet test --no-build -c Release

Nothing in that file references WarpBuild. The runner label selects the machine, and the cache traffic goes to GitHub. Every Windows label in the catalog behaves the same way on this point.

Windows labelImagevCPU / RAMPer minuteWarpBuild cacheCache action to use
warp-windows-latest-x64-4xWindows Server 20224 / 16 GB$0.016Not supportedactions/cache@v4
warp-windows-latest-x64-8xWindows Server 20228 / 32 GB$0.032Not supportedactions/cache@v4
warp-windows-latest-x64-16xWindows Server 202216 / 64 GB$0.064Not supportedactions/cache@v4
warp-windows-latest-x64-32xWindows Server 202232 / 128 GB$0.128Not supportedactions/cache@v4
warp-windows-2025-x64-8xWindows Server 20258 / 32 GB$0.032Not supportedactions/cache@v4
warp-windows-2025-vs2026-x64-8xWindows Server 2025 (VS 2026)8 / 32 GB$0.032Not supportedactions/cache@v4

Every rate and shape above comes from the cloud runners documentation, checked on 2026-08-13. All Windows labels carry 256GB SSD storage, and that storage is ephemeral, so it disappears when the runner terminates. Windows 2 vCPU runners were removed on June 8, 2026, which makes 4 vCPU the smallest Windows shape.

The per-minute rates for every platform are on the pricing page.

Detail

What "not supported" means once a job is running

The WarpBuild cache is a service the runner talks to, reached through the WarpBuilds/cache action and its restore and save variants. On a Linux runner the action finds the runner-side endpoint and the WARPBUILD_RUNNER_VERIFICATION_TOKEN environment variable that authenticates it. On a Windows runner that path is outside the supported set, so the honest move is to leave WarpBuilds/cache out of Windows jobs rather than add it and hope.

The same rule reaches further than the cache action itself. WarpBuild maintains drop-in replacements for the popular setup-* actions covering Node.js, Python, Go, Java, .NET, Ruby, Zig, Rust, Gradle, and mise, and those actions route toolchain and dependency caching through WarpBuild Cache underneath. On a Windows job, use the upstream actions/setup-* action and cache with actions/cache@v4. On a Linux job, the WarpBuilds/setup-* variants give you the WarpBuild cache with no workflow changes beyond the action name.

Docker layer caching through the WarpBuild cache proxy follows the same boundary, since it depends on the cache service the Windows fleet does not reach. Windows container builds and Windows Docker workloads are a separate topic from cache backends, and the layer cache question only arises where the WarpBuild cache runs.

The Windows replacement is GitHub's own Actions cache service

actions/cache@v4 authenticates with the cache credentials GitHub injects into every workflow run, so it works from a WarpBuild Windows runner exactly as it works anywhere else GitHub Actions executes. GitHub has updated its cache service for larger entries, and the size limits and expiration policy for your organization live under the organization Actions settings. The WarpBuild caching documentation calls this the recommended approach for most users, with WarpBuild cache reserved for advanced cases and BYOC on Linux.

Three details are worth setting up front on Windows.

Redirect the package cache to a short path. Windows path length limits bite hardest inside deeply nested package folders. Setting NUGET_PACKAGES to C:\nuget, as in the snippet above, keeps restored package paths short and gives actions/cache one stable directory to archive.

Key on a lock file, not on a branch. hashFiles('**/packages.lock.json') changes only when dependencies change, which is what makes a cache entry worth restoring. Turn on RestorePackagesWithLockFile so the lock files exist, then restore with -p:RestoreLockedMode=true so a drifted lock file fails the job instead of quietly re-resolving against the feed. The NuGet caching guide covers key design in full.

Include runner.os in the key. It costs nothing and it prevents a Linux entry and a Windows entry from ever competing for the same key.

Build-tool caches that live in the workspace

The second Windows path skips the cache service and keeps state where the build tool expects it.

MSBuild has a working incremental build system that compares timestamps against obj and bin output. Every GitHub Actions job starts on a fresh machine, so those directories are empty and every target rebuilds. Inside one job, though, incremental behavior is real: restore once, build once, and run tests against the already-built output with --no-build so the test step does not recompile the solution. Analyzer runs are the other lever, since analyzers rerun on projects nobody touched unless you scope them. The MSBuild caching guide works through both.

Anything you want to carry between jobs on Windows goes through actions/cache@v4 or actions/upload-artifact@v4. Runner storage is ephemeral on every WarpBuild platform, so nothing on the disk survives the job that wrote it.

Here is the shape most .NET repositories end up with once both legs exist. The Linux leg uses the WarpBuild setup action with caching switched on, which routes through the WarpBuild cache and needs a packages.lock.json to key against; the Windows leg uses the upstream action plus actions/cache@v4:

name: build-matrix

on:
  pull_request:

jobs:
  linux:
    runs-on: warp-ubuntu-latest-x64-4x
    steps:
      - uses: actions/checkout@v4

      - uses: WarpBuilds/setup-dotnet@v4
        with:
          dotnet-version: "9.0"
          cache: true
          cache-dependency-path: "**/packages.lock.json"

      - run: dotnet restore -p:RestoreLockedMode=true
      - run: dotnet build --no-restore -c Release
      - run: dotnet test --no-build -c Release

  windows:
    runs-on: warp-windows-2025-x64-8x
    env:
      NUGET_PACKAGES: C:\nuget
    steps:
      - uses: actions/checkout@v4

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

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

      - run: dotnet restore -p:RestoreLockedMode=true
      - run: dotnet build --no-restore -c Release
      - run: dotnet test --no-build -c Release

Two cache backends in one workflow is the normal end state for a cross-platform repository, and the split costs four lines of YAML.

The cross-OS archive note

Both actions/cache@v4 and WarpBuilds/cache@v1 expose an enableCrossOsArchive input. The WarpBuild caching documentation describes it as an optional boolean that, when enabled, allows Windows runners to save or restore caches that can be restored or saved on other platforms, with a default of false. Teams read that input and assume one entry can serve a Linux leg and a Windows leg. It usually cannot, for a reason that sits below the flag.

Cache entries carry a version, and the version is a hash over the compression tool the runner OS uses (gzip, zstd, and so on) together with the set of paths being cached. Entries with different versions are treated as different caches during matching. The documentation gives the concrete example: an entry saved on warp-macos-14-arm64-6x cannot be restored on warp-ubuntu-latest-x64-4x, because the versions differ.

enableCrossOsArchive addresses archive format compatibility. It does not collapse the version hash, and it does not rewrite paths. A Windows job caching C:\nuget and a Linux job caching ~/.nuget/packages are asking for different path sets, so they compute different versions and never match each other. On top of that, restored content is often platform-specific anyway: native binaries, symlink handling, and file permissions all differ.

The practical guidance is to give each operating system its own key prefix with runner.os, accept two entries, and spend the engineering time on key quality instead. Cross-OS restore is worth attempting only for content that is genuinely platform-neutral, such as a directory of downloaded source archives with identical relative paths on both sides.

What Windows caching costs

Windows jobs generate no WarpBuild cache line items, because their cache traffic goes to GitHub. That makes the arithmetic for a cross-platform repository easy to lay out. Every number below comes from the pricing page and the cloud runners documentation, checked on 2026-08-13.

Take a .NET repository that runs both legs on every pull request: 1,000 Windows jobs a month at 8 minutes each, and 1,000 Linux jobs a month at 4 minutes each.

  • Windows compute: 8,000 minutes on warp-windows-2025-x64-8x at $0.032 per minute = $256.00 per month.
  • Windows cache: $0.00 in WarpBuild charges. The entries live in GitHub's Actions cache service.
  • Linux compute: 4,000 minutes on warp-ubuntu-latest-x64-4x at $0.008 per minute = $32.00 per month.
  • Linux cache storage: 3 GB of live entries at $0.20 per GB-month = $0.60 per month.
  • Linux cache operations: one restore and one save per job, 2,000 operations at $0.0001 each = $0.20 per month.

Monthly total: $288.80, of which $0.80 is cache. WarpBuild cache entries expire after 7 days of last use and can be deleted from the action or the console, so the storage figure tracks live entries rather than everything ever written. On BYOC, cache storage and cache operations are included at no charge, and the compute is billed by your own cloud account.

The rest of the Windows runner surface

Caching is the one documented gap on Windows. The Windows x86-64 images carry the same tooling as GitHub-hosted runners, which is why moving a Windows job usually reduces to the runs-on line. The full label list, including the Windows Server 2025 and Visual Studio 2026 images, is in the Windows runner catalog.

Does the WarpBuild cache work on Windows runners?

No. The caching documentation lists WarpBuild caching as not supported for Windows-based runners, and the cloud runners documentation repeats it. WarpBuild cache is enabled by default on Linux runners only. A Windows job caches through actions/cache@v4 instead, and the Windows runner catalog lists every Windows label this applies to.

What should a Windows GitHub Actions job use for caching instead?

actions/cache@v4, which writes to GitHub's own Actions cache service using the credentials GitHub injects into every workflow run, so it needs no extra configuration on a WarpBuild Windows runner. Pair it with a build-tool cache such as the NuGet global packages folder redirected to a short path, covered in the NuGet caching guide.

Can a cache saved on a Windows runner be restored on Linux?

Rarely, and it takes work. The enableCrossOsArchive input lets a Windows runner save an archive other platforms can read, but the cache version hash still covers the compression tool and the cached paths, so entries with different versions never match. Key entries per operating system with runner.os instead.

Do the WarpBuilds setup- actions cache on Windows runners?*

No. Those drop-in setup actions use WarpBuild Cache underneath, and WarpBuild Cache is unsupported on Windows. Keep the upstream actions/setup-* action plus actions/cache@v4 on Windows jobs, and use the WarpBuilds/setup-* variants on Linux jobs. The MSBuild caching guide shows the Windows side end to end.

Pick a Windows label from the Windows runner catalog, confirm the platform fits your build in can GitHub Actions run Windows builds, and price the change against your own job 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.