Unreal Engine Builds on GitHub Actions

Unreal Engine builds on GitHub Actions run on WarpBuild Windows runners at 16 and 32 vCPU with 256GB SSDs, priced at $0.064 and $0.128 per minute.

Last verified:

An Unreal Engine build on GitHub Actions needs a Windows runner with enough cores to feed the shader compile workers and the cook commandlet, enough disk for the engine plus the content tree, and a derived data cache that survives between jobs. WarpBuild provides Windows runners from 4 to 32 vCPU, every size carrying a 256GB SSD, at $0.016 to $0.128 per minute, selected by pointing runs-on at a label such as warp-windows-latest-x64-32x.

The sections below give a working pipeline with the DDC directory pinned and UnrealBuildTool invoked directly, the per-minute arithmetic against GitHub-hosted Windows larger runners, a disk budget for the 256GB working set, and the four bottlenecks that dominate Unreal pipelines.

Overview

An Unreal pipeline on GitHub Actions spends its minutes in five places: syncing the project and its binary content, compiling the engine and game targets through UnrealBuildTool, compiling shaders, cooking content for the target platform, and staging or packaging the result. The first is network bound. Compilation and shader work scale across cores. Cook is bound by the derived data cache and by disk. Staging is large sequential I/O.

WarpBuild provides Linux x64, Linux ARM64, macOS, and Windows runners. Unreal editor and Win64 targets need the Windows fleet, which comes in three image families at four sizes each, from 4 to 32 vCPU, all with 256GB SSDs: Windows Server 2022 under warp-windows-latest-x64-<size>, Windows Server 2025 under warp-windows-2025-x64-<size>, and Windows Server 2025 with Visual Studio 2026 under warp-windows-2025-vs2026-x64-<size>. The full matrix lives in the cloud runners documentation and on the Windows runner hub.

Every runner is an ephemeral VM, freshly allocated for the job and destroyed afterward. The images carry the same tooling as GitHub-hosted Windows images, so the MSVC toolchain and the Windows SDK are present without setup steps. The engine itself is not part of any hosted image, so the job either fetches a prebuilt engine from your own artifact storage or builds the engine from source once and reuses that artifact.

Two platform limits shape every design decision on this page. WarpBuild caching is not supported on Windows runners, so the derived data cache moves through actions/cache or through a DDC endpoint you host. Snapshot runners are supported on Ubuntu cloud runners only, so a warm-disk snapshot of an engine build is unavailable on the Windows path.

Configuration

Here is a Windows pipeline on warp-windows-latest-x64-32x. It fetches a prebuilt engine, checks out the project with Git LFS content, keeps the local DDC on the workspace drive, and runs UnrealBuildTool and BuildCookRun in the same job so the DDC stays warm between the two.

name: unreal

on:
  push:
    branches: [main]
  pull_request:

env:
  UE_ROOT: C:\UnrealEngine
  UPROJECT: ${{ github.workspace }}\Game\Game.uproject
  DDC_DIR: ${{ github.workspace }}\DerivedDataCache

jobs:
  build-cook-stage:
    runs-on: warp-windows-latest-x64-32x
    timeout-minutes: 240
    steps:
      - uses: actions/checkout@v4
        with:
          lfs: true

      - name: Fetch the prebuilt engine
        shell: pwsh
        run: |
          Invoke-WebRequest -Uri "$env:ENGINE_ARTIFACT_URL" -OutFile engine.zip
          Expand-Archive engine.zip -DestinationPath "$env:UE_ROOT"
        env:
          ENGINE_ARTIFACT_URL: ${{ secrets.ENGINE_ARTIFACT_URL }}

      - uses: actions/cache@v4
        with:
          path: ${{ env.DDC_DIR }}
          key: ddc-win64-${{ github.sha }}
          restore-keys: |
            ddc-win64-

      - name: Build the editor and game targets
        shell: pwsh
        run: |
          New-Item -ItemType Directory -Force -Path "$env:DDC_DIR" | Out-Null
          ${env:UE-LocalDataCachePath} = $env:DDC_DIR
          & "$env:UE_ROOT\Engine\Build\BatchFiles\Build.bat" `
            GameEditor Win64 Development -Project="$env:UPROJECT" -WaitMutex
          & "$env:UE_ROOT\Engine\Build\BatchFiles\Build.bat" `
            Game Win64 Development -Project="$env:UPROJECT" -WaitMutex

      - name: Cook, stage, and package
        shell: pwsh
        run: |
          ${env:UE-LocalDataCachePath} = $env:DDC_DIR
          & "$env:UE_ROOT\Engine\Build\BatchFiles\RunUAT.bat" BuildCookRun `
            -project="$env:UPROJECT" `
            -platform=Win64 -clientconfig=Development `
            -nop4 -utf8output -nocompileeditor `
            -cook -stage -pak -archive `
            -archivedirectory="${{ github.workspace }}\Archive"

Four details carry the build.

Pin the local DDC inside the workspace. By default Unreal writes its local derived data cache under the user profile, which puts it outside the paths actions/cache is told about and can put it on a different volume from the checkout. Setting UE-LocalDataCachePath to a workspace directory gives the cache step one deterministic path and keeps DDC reads and writes on the same 256GB SSD as the project. PowerShell needs the brace form, ${env:UE-LocalDataCachePath}, because the variable name contains a hyphen.

Cache the DDC with actions/cache, and size it against the 10 GB limit. WarpBuild caching covers Linux runners, so Windows jobs use GitHub's cache service. Entries count against GitHub's 10 GB per-repository cache limit, and a full-project DDC for a content-heavy title exceeds that ceiling. Cache the DDC for the subset of platforms a pull request actually cooks, evict aggressively with a per-commit key and a broad restore-keys prefix, and move the whole-project DDC to a shared endpoint once it stops fitting.

Run build and cook in one job. UnrealBuildTool output under Intermediate and Binaries, and the DDC entries the editor produces while compiling shaders, are all local to the VM. Splitting build and cook into two GitHub Actions jobs pays VM boot, engine fetch, and DDC restore twice, and the second job starts with a cold DDC that the first job just populated. Keep them in one job, as above, and reserve separate jobs for genuinely parallel work such as per-platform cooks.

Check out LFS content deliberately. lfs: true pulls every LFS object in the repository. On large content trees, restrict what a pull request job pulls with sparse checkout on the content directories the build needs, and let the nightly full-cook job pull everything.

The default shell on Windows runners is PowerShell, so backslash paths and backtick line continuations work as written. Pin the image family with warp-windows-2025-vs2026-x64-32x when the engine build requires the Visual Studio 2026 toolset.

Sizing

The Windows catalog, with per-minute rates from the WarpBuild pricing page:

Runner labelOSvCPUMemoryStoragePrice per minute
warp-windows-latest-x64-4xWindows Server 2022416 GB256GB SSD$0.016
warp-windows-latest-x64-8xWindows Server 2022832 GB256GB SSD$0.032
warp-windows-latest-x64-16xWindows Server 20221664 GB256GB SSD$0.064
warp-windows-latest-x64-32xWindows Server 202232128 GB256GB SSD$0.128

The warp-windows-2025-x64-<size> and warp-windows-2025-vs2026-x64-<size> labels come in the same four sizes at the same rates. Windows 2 vCPU runners were removed on June 8, 2026, so 4 vCPU is the smallest Windows size.

Unreal work sorts into three sizing tiers.

Editor and game target compiles keep every core busy while UnrealBuildTool schedules translation units, then narrow to link steps that use one core each. warp-windows-latest-x64-16x is the working default for pull request compile checks.

Cook plus shader compilation is where 32 vCPU pays. The cook commandlet fans work out to shader compile workers, one process group per available core by default, and a cold DDC turns the cook into a shader compilation job. warp-windows-latest-x64-32x with 128 GB of memory holds the worker set without paging.

Packaging and archive steps are sequential I/O over pak files and staged content. Cores sit idle here, so a workflow that separates archive from cook can drop the archive job to warp-windows-latest-x64-8x, provided the artifacts move through storage rather than through the local disk of a second machine.

List-price arithmetic against GitHub-hosted Windows runners

GitHub publishes per-minute list prices for its Windows larger runners. The two sizes that matter for Unreal:

WarpBuild runnerShapeWarpBuild per minuteGitHub-hosted equivalentGitHub per minuteArithmeticLower list price
warp-windows-latest-x64-16x16 vCPU, 64 GB$0.06416-core Windows larger runner$0.082(0.082 - 0.064) / 0.08222 percent
warp-windows-latest-x64-32x32 vCPU, 128 GB$0.12832-core Windows larger runner$0.162(0.162 - 0.128) / 0.16221 percent

GitHub rates are from the GitHub Actions minute multipliers reference, checked on 2026-08-13. Both sides carry the same vCPU and memory shape.

Take a title whose main-branch cook and package pipeline consumes 12,000 Windows runner-minutes per month on 32 vCPU machines:

Line itemRateVolumeMonthly cost
GitHub-hosted 32-core Windows larger runner$0.162 per minute12,000 minutes$1,944.00
warp-windows-latest-x64-32x$0.128 per minute12,000 minutes$1,536.00

The WarpBuild total is $1,536.00 against $1,944.00 for the same minutes, a difference of $408.00 per month. The model holds minutes equal on both sides. actions/cache uses GitHub's cache service, which carries no per-operation charge, so runner minutes are the whole WarpBuild bill in this shape.

Full rates for every size and platform are on the pricing page.

The 256GB working set

Every Windows size ships the same 256GB SSD, so the budget is fixed and the question is what shares it.

What lands on the runner diskWhere it comes fromCan it move off the runner
Engine binaries and engine DDCFetched per job from your artifact storagePartly, by fetching only the target platforms you cook
Project checkout and Git LFS contentactions/checkout with lfs: trueYes, with sparse checkout scoped to the directories the job builds
Intermediate and BinariesProduced by UnrealBuildToolNo, the toolchain writes them locally
Local DDCProduced by the editor and the cook commandletYes, with a shared DDC endpoint in place of the local path
Saved/Cooked, Saved/StagedBuilds, pak filesProduced by BuildCookRunYes, archive to storage inside the job and delete before the next stage

A single-platform Win64 cook of a mid-size project fits this budget with room to spare. A run that cooks several platforms in one job, keeps every staged build on disk, and holds a whole-project DDC alongside them is the shape that runs the disk out. Two fixes work: archive and delete cooked output between platforms in the same job, and move the DDC off the local disk.

Teams whose content tree needs local NVMe throughput beyond what the shared budget allows run BYOC instead. BYOC runs on AWS, GCP, and Azure, and Terraform support exists for BYOC on AWS. Windows BYOC runner sets are available on AWS and Azure at $0.002 per minute of orchestration, so the instance type and its disk configuration are yours to pick. One caveat matters here: automatic local NVMe detection and mounting is documented for Linux images only, and the local SSD documentation lists Windows and macOS as unsupported. A Windows BYOC instance with instance-store NVMe therefore needs the volume prepared in your own image. The hosted and BYOC comparison covers the tradeoff and cost model in full.

Bottlenecks

Four bottlenecks account for most slow Unreal pipelines on GitHub Actions.

Derived data cache misses. The DDC holds the compiled shaders, cooked textures, and processed meshes that the editor and the cook commandlet would otherwise regenerate. On an ephemeral runner with an empty DDC, every cook regenerates the whole set. A cache key tied to the commit gives an exact hit only for a rerun of the same commit, so the restore-keys prefix matters more than the key: it pulls the nearest previous DDC and leaves the cook regenerating only what changed. When the DDC outgrows GitHub's 10 GB per-repository cache limit, a hosted shared DDC endpoint configured through the backend graph is the next step, and it removes the restore and save minutes from the job as well.

Shader compilation. Shader permutations are the largest single generator of derived data in most projects. Material changes, engine upgrades, and new target platforms all invalidate wide swaths of the permutation set at once, which is why the first build after an engine bump costs far more than the diff suggests. Shader compile workers scale across cores, so this is the phase that justifies 32 vCPU, and it is also the phase that a warm DDC removes almost entirely.

Cook time on large content trees. The cook commandlet walks every referenced asset, converts it for the target platform, and writes the result. Its cost tracks the number of referenced assets, so asset registry hygiene shows up directly in the bill: unreferenced content pulled in by a stray hard reference gets cooked with everything else. Cooking one platform per job, with chunked pak output, keeps each job's asset set bounded.

Disk throughput. Unreal's build and cook phases are heavy on small-file I/O against Intermediate, the DDC, and Saved/Cooked, all on the same 256GB SSD. When a job stalls with cores idle and disk queues deep, the fix is to reduce what shares the volume rather than to add cores: archive staged output early, scope the LFS checkout, and keep the DDC either warm or remote.

Telling these apart is a measurement problem. WarpBuild's CI observability streams system metrics from the runner and correlates them with GitHub Actions job logs, so a cook stuck on single-threaded asset iteration looks visibly different from a shader compile saturating all 32 cores. The Action Debugger opens a shell on a failing job, which is the fastest way to inspect a cook log and a DDC directory in place instead of guessing across reruns.

Proof

The runner-side agent is open source at github.com/WarpBuilds/warpbuild-agent, and the cloud runners documentation publishes the full Windows catalog with prices, image contents, and change history for independent verification. Sibling coverage for the other major engine is on the Unity builds page, and the caching mechanics behind the MSVC side of an engine build are in the MSBuild caching guide.

FAQ

Which WarpBuild Windows runner size fits an Unreal Engine build?

Compile-only jobs that run UnrealBuildTool and nothing else fit warp-windows-latest-x64-16x at $0.064 per minute. Jobs that cook content and compile shaders in the same run belong on warp-windows-latest-x64-32x at $0.128 per minute, because the cook commandlet and the shader compile workers both scale across cores.

Can the WarpBuild cache hold the Unreal derived data cache on Windows?

No. WarpBuild caching is not supported on Windows runners. Cache the local DDC directory with actions/cache, which stores entries in GitHub's cache service under the 10 GB per-repository limit, or point the DDC backend graph at a shared DDC endpoint you host.

Is 256GB of runner disk enough for an Unreal project?

Every WarpBuild Windows size ships a 256GB SSD. The engine build, the Git LFS checkout, Intermediate and Binaries, the local DDC, and the staged output all land on that one disk, so archive cooked output to storage inside the job and delete it before the next stage.

Can Unreal builds run on BYOC runners in our own cloud account?

Yes. BYOC runs on AWS, GCP, and Azure, and Windows BYOC runner sets are available on AWS and Azure at $0.002 per minute of orchestration. Automatic local NVMe mounting is documented for Linux images only, so Windows BYOC instances do not get it.

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.