Skip to main content
Version: v4 (current)

Custom Images

Build Unity editor Docker images with custom module combinations using the GameCI CLI.

Why Custom Images?

The pre-built unityci/editor images ship with a single module per image (e.g. android, windows-mono, linux-il2cpp). Some projects need multiple modules installed together — for example, when third-party packages like Wwise or FMOD include native plugins for multiple platforms that Unity resolves during the import phase.

Quick Start

# Install the CLI
curl -fsSL https://raw.githubusercontent.com/game-ci/cli/main/install.sh | sh

# Build a desktop combo image (Windows + Linux IL2CPP + Mac)
game-ci build-unity-image ubuntu windows-mono,linux-il2cpp,mac-mono \
--unity-version 2022.3.20f1

# Build and push to your registry
game-ci build-unity-image ubuntu windows-mono,linux-il2cpp \
--unity-version 2022.3.20f1 \
--tag ghcr.io/my-org/unity-editor:desktop \
--push

# Build a Windows-based editor image
game-ci build-unity-image windows windows-mono,mac-mono \
--unity-version 2022.3.20f1

Usage

game-ci build-unity-image [baseOs] [modules] [options]

Positional Arguments

ArgumentDefaultDescription
baseOsubuntuBase operating system (ubuntu or windows)
modulesbaseComma-separated Unity modules to install

Options

FlagDefaultDescription
--unity-version(required)Unity editor version (e.g. 2022.3.20f1)
--changeset(auto-resolved)Unity changeset hash
--tag(auto-generated)Docker image tag
--pushfalsePush image to registry after building
--hub-imageunityci/hubHub base image
--base-imageunityci/baseEditor base image

The CLI also supports baseOs=windows. When you select windows, the command uses the Windows Hub and base image defaults unless you override them with --hub-image and --base-image.

Available Modules

ModuleDescription
baseEditor only (Linux Mono built-in)
linux-il2cppLinux IL2CPP build support
windows-monoWindows Mono build support
mac-monomacOS Mono build support
iosiOS build support
androidAndroid build support
webglWebGL build support

GitHub Actions Example

Build-and-use locally (no registry needed)

Most projects don't need to publish their Unity editor image — build it as a CI step, tag it locally, and reference that local tag in the same job. The image lives only in the runner's Docker daemon for the lifetime of the job:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install GameCI CLI
run: curl -fsSL https://raw.githubusercontent.com/game-ci/cli/main/install.sh | sh

- name: Build custom Unity image
run: |
game-ci build-unity-image ubuntu windows-mono,linux-il2cpp \
--unity-version 2022.3.20f1 \
--tag unity-editor:desktop

- uses: game-ci/unity-builder@v4
with:
customImage: unity-editor:desktop
targetPlatform: StandaloneWindows64

No GHCR account, no docker login, no pushed bytes. The image never leaves the runner.

Build cost and caching

The CLI invokes docker build directly. Image build time is dominated by Unity Hub installing the editor and modules — expect 15-30 minutes for typical desktop combos. On GitHub-hosted runners that work is repeated every job because the runner (and its Docker daemon) is destroyed at the end of each run.

If that rebuild cost is acceptable for your cadence, you're done. Otherwise pick one of:

StrategyWhat you set upBest for
Self-hosted runnerA persistent runner whose Docker daemon retains layers between jobsTeams already running self-hosted infrastructure
Push once, pull thereafterBuild the image in a scheduled workflow, push to GHCR, pull in build workflowsStable module combos used by many runs
Buildx + GHA cache backendWrap the build with docker/setup-buildx-action and a cache-aware build stepFrequent module/version churn on hosted runners

The push-once strategy is covered below. For self-hosted runner caching, see the orchestrator caching guide.

Pre-built (push once, pull forever)

When the same image is used across many workflows, repos, or runs, push it to a registry once and reference it everywhere:

# Run once (or on a schedule)
jobs:
build-image:
runs-on: ubuntu-latest
steps:
- name: Install GameCI CLI
run: curl -fsSL https://raw.githubusercontent.com/game-ci/cli/main/install.sh | sh

- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
run: |
game-ci build-unity-image ubuntu windows-mono,linux-il2cpp \
--unity-version 2022.3.20f1 \
--tag ghcr.io/${{ github.repository_owner }}/unity-editor:desktop \
--push

Then in your build workflow:

- uses: game-ci/unity-builder@v4
with:
customImage: ghcr.io/my-org/unity-editor:desktop
targetPlatform: StandaloneWindows64

Common Combinations

NameModulesUse case
Desktopwindows-mono,linux-il2cpp,mac-monoWwise/FMOD, Steam multi-platform
Windows desktopwindows-mono,mac-monoWindows-hosted plugin workflows
Desktop + Androidwindows-mono,linux-il2cpp,androidMeta Quest + PC VR
Mobileandroid,iosMulti-platform mobile

How It Works

The CLI generates a Dockerfile that mirrors the game-ci/docker build pipeline, including all version-specific patches:

  • Android SDK setup (2018.x legacy through 6000+)
  • IL2CPP build tool fixes (2019.3.x)
  • WebGL dependencies (python2, ffmpeg, brotli, build-essential)
  • Mac-mono symlink fixes (2021-2022)
  • Server module auto-installation (2021.2.5+)

The generated image is identical to what game-ci/docker CI produces.