Skip to main content
Version: v4 (current)

Getting started

GitHub Actions for Unity provide the fastest and easiest way to automatically test and build any Unity project.

There are a few parts to setting up a workflow. Steps may slightly differ depending on each license type.

Mental model

Overall steps

  1. Understand how Github Actions work.
  2. Configure a license for Unity.
  3. Set up a workflow for your project.
  4. Result: Merge pull requests with more confidence.

Setting up a workflow

Setting up a workflow is easy!

Create a file called .github/workflows/main.yml in your repository and configure the following steps;

  1. Checkout your repository using Checkout.
  2. Cache Unity Library folder using Cache.
  3. Configure your test job using Test Runner.
  4. Configure your build job using Builder.
  5. Deploy your application.

Note: all steps will be explained in the next chapters.

Support

First time using GitHub Actions?

Read the official documentation on how to setup a workflow.

Any subsequent steps assume you have read the above.

Supported Unity versions

Unity Actions are using game-ci/docker since unity-builder version 2. Any version in this list can be used.

Video Tutorial

Note: The video tutorial was created using an earlier version of the GameCI GitHub Actions for Unity. While it provides a helpful visual guide to understanding the process, please refer to the current documentation on this website for the most up-to-date information.

Workflow examples

Below are workflow examples displaying various levels of complexity.

It is recommended to start from the Simple Example and work your way down the page.

Simple example

This example tests your project then builds it for a single target (WebGL in this case). It will run sequentially.

This example assumes that your Unity project is in the root of your repository.

name: Actions 😎

on: [push, pull_request]

jobs:
build:
name: Build my project ✨
runs-on: ubuntu-latest
steps:
# Checkout
- name: Checkout repository
uses: actions/checkout@v4
with:
lfs: true

# Cache
- uses: actions/cache@v3
with:
path: Library
key: Library-${{ hashFiles('Assets/**', 'Packages/**', 'ProjectSettings/**') }}
restore-keys: |
Library-

# Test
- name: Run tests
uses: game-ci/unity-test-runner@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}

# Build
- name: Build project
uses: game-ci/unity-builder@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
targetPlatform: WebGL

# Output
- uses: actions/upload-artifact@v3
with:
name: Build
path: build

Simple example with Git LFS

If you are using GitHub's git-lfs hosting service to store your large binary assets, you will want to cache them to avoid consuming massive amounts of bandwidth. The extra steps in this example try to restore your git-lfs assets from a cache before doing a git lfs pull.

name: Actions 😎

on: [push, pull_request]

jobs:
build:
name: Build my project ✨
runs-on: ubuntu-latest
steps:
# Checkout (without LFS)
- name: Checkout repository
uses: actions/checkout@v4

# Git LFS
- name: Create LFS file list
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id

- name: Restore LFS cache
uses: actions/cache@v3
id: lfs-cache
with:
path: .git/lfs
key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}

- name: Git LFS Pull
run: |
git lfs pull
git add .
git reset --hard

# Cache
- uses: actions/cache@v3
with:
path: Library
key: Library-${{ hashFiles('Assets/**', 'Packages/**', 'ProjectSettings/**') }}
restore-keys: |
Library-

# Test
- name: Run tests
uses: game-ci/unity-test-runner@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}

# Build
- name: Build project
uses: game-ci/unity-builder@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
targetPlatform: WebGL

# Output
- uses: actions/upload-artifact@v3
with:
name: Build
path: build

Parallel execution of Tests and Builds

This will run tests in parallel with the Build, in this case for Windows 64bit.

This example assumes that your Unity project is in the root of your repository.

name: Actions 😎

on: [push, pull_request]

jobs:
test:
name: Test my project 🧪
runs-on: ubuntu-latest
steps:
# Checkout
- name: Checkout repository
uses: actions/checkout@v4
with:
lfs: true

# Cache
- uses: actions/cache@v3
with:
path: Library
key: Library-${{ hashFiles('Assets/**', 'Packages/**', 'ProjectSettings/**') }}
restore-keys: |
Library-

# Test
- name: Run tests
uses: game-ci/unity-test-runner@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}

build:
name: Build my project ✨
runs-on: ubuntu-latest
steps:
# Checkout
- name: Checkout repository
uses: actions/checkout@v4
with:
lfs: true

# Cache
- uses: actions/cache@v3
with:
path: Library
key: Library-${{ hashFiles('Assets/**', 'Packages/**', 'ProjectSettings/**') }}
restore-keys: |
Library-

# Build
- name: Build project
uses: game-ci/unity-builder@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
targetPlatform: StandaloneWindows64
allowDirtyBuild: true

# Output
- uses: actions/upload-artifact@v3
with:
name: Build
path: build

Advanced IL2CPP example

This example leverages the powerful Github Actions construct called a matrix to test and build for multiple versions of Unity and several target platforms in parallel.

IL2CPP builds require the base operating system to match the build target.

Below is an example to build for all supported platforms with the IL2CPP scripting backend enabled in the project settings.

Note: Tests are currently only compatible on Linux hosts.

name: Actions 😎

on: [push, pull_request]

jobs:
buildAndTestForLinuxBasedPlatforms:
name: Build for ${{ matrix.targetPlatform }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
projectPath:
- test-project
unityVersion:
- 2019.4.1f1
- 2020.2.1f1
targetPlatform:
- StandaloneLinux64 # Build a Linux 64-bit standalone.
- iOS # Build an iOS player.
- Android # Build an Android player.
- WebGL # WebGL.
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
lfs: true
- uses: actions/cache@v3
with:
path: ${{ matrix.projectPath }}/Library
key:
Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}-${{
hashFiles(matrix.projectPath) }}
restore-keys: |
Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}-
Library-${{ matrix.projectPath }}-
Library-
- uses: game-ci/unity-test-runner@v4
id: testRunner
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
githubToken: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-artifact@v3
if: always()
with:
name: Test results (all modes)
path: ${{ steps.testRunner.outputs.artifactsPath }}
- if: matrix.targetPlatform == 'Android'
uses: jlumbroso/free-disk-[email protected]
- uses: game-ci/unity-builder@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
targetPlatform: ${{ matrix.targetPlatform }}
customParameters: '-myParameter myValue -myBoolean -ThirdParameter andItsValue'
- uses: actions/upload-artifact@v3
with:
name: Build
path: build

buildForWindowsBasedPlatforms:
name: Build for ${{ matrix.targetPlatform }}
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
projectPath:
- test-project
unityVersion:
- 2019.4.1f1
- 2020.2.1f1
targetPlatform:
- StandaloneWindows # Build a Windows 32-bit standalone.
- StandaloneWindows64 # Build a Windows 64-bit standalone.
- tvOS # Build an AppleTV player.
- WSAPlayer # Build a UWP App.

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
lfs: true
- uses: actions/cache@v3
with:
path: ${{ matrix.projectPath }}/Library
key:
Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}-${{
hashFiles(matrix.projectPath) }}
restore-keys: |
Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}-
Library-${{ matrix.projectPath }}-
Library-
- uses: game-ci/unity-builder@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
targetPlatform: ${{ matrix.targetPlatform }}
customParameters: '-myParameter myValue -myBoolean -ThirdParameter andItsValue'
- uses: actions/upload-artifact@v3
with:
name: Build
path: build

buildForMacOSBasedPlatforms:
name: Build for ${{ matrix.targetPlatform }}
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
projectPath:
- test-project
unityVersion:
- 2019.4.1f1
- 2020.2.1f1
targetPlatform:
- StandaloneOSX # Build a macOS standalone.

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
lfs: true

- uses: actions/cache@v3
with:
path: ${{ matrix.projectPath }}/Library
key:
Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}-${{
hashFiles(matrix.projectPath) }}
restore-keys: |
Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}-
Library-${{ matrix.projectPath }}-
Library-

- uses: game-ci/unity-builder@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
targetPlatform: ${{ matrix.targetPlatform }}
customParameters: '-myParameter myValue -myBoolean -ThirdParameter andItsValue'

- uses: actions/upload-artifact@v3
with:
name: Build
path: build