Skip to content
Latchkey

CI/CD for a Zig Build Project with GitHub Actions

Install a pinned Zig, run zig build test, and cross-compile release binaries on a tag.

This recipe builds a Zig project with the standard build system. CI installs a pinned Zig version, runs zig build test, and on a tag cross-compiles release binaries for several targets using Zig's built-in cross toolchain.

What the pipeline does

  • install a pinned Zig version
  • run zig build test
  • build with -Doptimize=ReleaseSafe
  • on a tag, cross-compile a target matrix
  • upload binaries as artifacts or release assets

The workflow

mlugg/setup-zig installs and caches Zig. zig build supports -Dtarget for cross-compilation without external toolchains, so one runner builds every target.

.github/workflows/ci.yml
name: CI
on:
  push:
    branches: [main]
    tags: ["v*"]
  pull_request:
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: mlugg/setup-zig@v2
        with:
          version: 0.13.0
      - run: zig build test
      - run: zig build -Doptimize=ReleaseSafe
  release:
    needs: build
    if: startsWith(github.ref, 'refs/tags/v')
    runs-on: ubuntu-latest
    permissions:
      contents: write
    strategy:
      matrix:
        target: [x86_64-linux, aarch64-linux, x86_64-macos, aarch64-macos]
    steps:
      - uses: actions/checkout@v4
      - uses: mlugg/setup-zig@v2
        with:
          version: 0.13.0
      - run: zig build -Doptimize=ReleaseSafe -Dtarget=${{ matrix.target }} --prefix dist
      - uses: softprops/action-gh-release@v2
        with:
          files: dist/bin/*

Caching and speed

setup-zig caches the Zig compiler and the global cache (~/.cache/zig). Cross-compiling four targets is CPU bound; cheaper managed runners such as Latchkey $0.0025/min at 2 vCPU against $0.006 GitHub-hosted cut release time and auto-retry a flaky compiler download.

Release output

Pin the exact Zig version since the language and build API still change between releases. zig build -Dtarget cross-compiles from a single Linux runner, and action-gh-release attaches each target's binary to the tag release.

Making this reliable in CI

  • Pin every tool version. An unpinned toolchain turns a runner image update into a build break on unchanged code.
  • Cache what is expensive to produce, and key the cache to the tool version so a restore across a version boundary cannot poison the build.
  • Assert on the produced artifact rather than on the command succeeding.
  • Set an explicit timeout so a hung step fails fast instead of consuming the whole job budget.

Key takeaways

  • Pin the Zig version exactly since the build API still evolves.
  • Use -Dtarget to cross-compile every target from one runner.
  • Run zig build test on PRs before any release build.

Frequently asked questions

CI/CD for a Zig Build Project with GitHub Actions?
This recipe builds a Zig project with the standard build system. CI installs a pinned Zig version, runs zig build test, and on a tag cross-compiles release binaries for several targets using Zig's built-in cross toolchain.
The workflow?
mlugg/setup-zig installs and caches Zig. zig build supports -Dtarget for cross-compilation without external toolchains, so one runner builds every target.
Caching and speed?
setup-zig caches the Zig compiler and the global cache (~/.cache/zig). Cross-compiling four targets is CPU bound; cheaper managed runners such as Latchkey $0.0025/min at 2 vCPU against $0.006 GitHub-hosted cut release time and auto-retry a flaky compiler download.
Release output?
Pin the exact Zig version since the language and build API still change between releases. zig build -Dtarget cross-compiles from a single Linux runner, and action-gh-release attaches each target's binary to the tag release.

Related guides

References

Run this faster and cheaper on Latchkey managed runners - self-healing included. Start free → 30-day trial · No credit card