Skip to content

Tuist Module Cache

Avrea's Tuist integration stores binary module artifacts in the colocated build cache. A warm artifact can be reused by later jobs and workflow runs for the same repository instead of rebuilding that module from source.

Available on macOS runners only. The integration is off by default.

Turn on Tuist Module Cache at the organization or repository level under Settings in the Avrea console. You can also use the CLI:

Terminal window
avr settings set cache.tuist-module.enabled true

The setting applies to new jobs. A job that is already running keeps its current environment. It authorizes the cache and configures new Avrea jobs; it does not enable remote-cache usage inside the Tuist project.

Add a stable fullHandle to Tuist.swift. It namespaces the cache artifacts and does not need to identify a project registered with Avrea or Tuist Cloud. If the project already has a fullHandle, preserve it.

Tuist.swift
import ProjectDescription
let tuist = Tuist(
fullHandle: "my-organization/my-project"
)

Cacheable targets include frameworks, libraries, bundles, and Swift macros. Application and test targets are not stored as module-cache artifacts, but the frameworks and libraries they depend on can be. See the Tuist module cache guide for the complete eligibility and project-configuration rules.

Avrea injects TUIST_CACHE_ENDPOINT and TUIST_TOKEN before workflow steps run. Do not add a cache token secret or override the endpoint. If your workflow already defines TUIST_TOKEN, Avrea preserves it.

Tuist itself must still be installed in the job. The examples below use jdx/mise-action and assume the Tuist version is pinned in .mise.toml or .tool-versions. Adapt that step if the project installs Tuist another way.

Tuist recommends a dedicated cache-warming job for every commit to the main branch. The job builds eligible targets and uploads complete module artifacts that later development and CI jobs can substitute.

If the project declares Swift package dependencies in Tuist/Package.swift, add the optional dependency-installation steps shown below before warming.

warm-tuist-cache.yml
name: Warm Tuist caches
on:
push:
branches: [main]
jobs:
warm:
runs-on: avrea-macos-latest
steps:
- uses: actions/checkout@v6
- name: Install Tuist
uses: jdx/mise-action@v2
- name: Warm Tuist module cache
run: tuist cache warm

Keep the warming command at the end of its dedicated job. Tuist modifies the generated workspace while warming; a later step that needs the workspace must run tuist generate again first.

The cache profile controls which targets Tuist warms and substitutes. Omitting --cache-profile uses the project's configured profile or Tuist's default. Use --cache-profile only-external to limit the cache to external packages, or --cache-profile all-possible to include as many eligible internal targets as possible. Preserve the profile already selected by the project unless you intend to change that behavior.

Pull-request jobs install Tuist and run their normal generation, build, and test commands without warming the remote module cache. Add the same optional dependency-installation steps before generation when the project uses Tuist/Package.swift.

pull-request.yml
name: Pull request
on:
pull_request:
jobs:
build:
runs-on: avrea-macos-latest
steps:
- uses: actions/checkout@v6
- name: Install Tuist
uses: jdx/mise-action@v2
- name: Generate project
run: tuist generate --no-open
- name: Run tests
run: tuist test

Adapt the final generation, build, and test commands to the project. The important division is that main warms the module cache and pull requests consume the latest compatible artifacts.

The Tuist module cache works independently from Swift package source caching. Projects without dependencies in Tuist/Package.swift do not need this section. For projects that have them, add the following steps after installing Tuist in both the warming and pull-request jobs.

Avrea automatically configures its Swift Package Registry as the default and associates the reserved avrea-com scope used by eligible private packages. The same managed configuration is available to Tuist, so normal workflows do not need to associate public scopes. Restore Tuist's installed dependency state with GitHub Actions Cache:

Tuist dependency steps
- name: Restore Tuist dependencies
id: tuist-dependencies
uses: actions/cache@v4
with:
path: |
Tuist/.build
Tuist/Package.resolved
key: tuist-install-v2-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('Tuist/Package.swift', 'Tuist/Package.resolved', 'Tuist.swift', '.mise.toml', '.tool-versions', '.xcode-version') }}
- name: Install Tuist dependencies
if: steps.tuist-dependencies.outputs.cache-hit != 'true'
run: >-
tuist install
--replace-scm-with-registry
--force-resolved-versions

This assumes Tuist/Package.resolved is committed. Direct registry identities and eligible semantic-version GitHub URL dependencies use the registry. Branch and commit dependencies continue to use Git. The Swift Package Registry guide contains the complete identity, scope, and fallback matrix.

Each layer avoids a different kind of work:

LayerWhat it storesWhen it is usedIsolationAvrea storage
GitHub Actions cacheTuist/.build and Tuist/Package.resolved dependency stateRestores installed dependencies before tuist installRepository-scoped, subject to GitHub branch and ref visibility rulesPrivate GitHub Actions cache
Swift package registryPackage source archives, manifests, versions, and checksumsSupplies eligible semantic-version public and private packages during tuist installPublic packages are shared; private packages are organization-isolatedPublic package storage or private artifact storage
Tuist module cacheComplete prebuilt binaries for eligible project and dependency targetsSubstitutes an entire target during project generation and buildsRepository-isolatedPrivate tuist-module-build cache
Xcode compilation cacheReusable compiler outputs for project source and directly built packagesSpeeds up eligible source compilation when a complete Tuist module is unavailableRepository-isolatedPrivate xcode-build cache

The Tuist module cache and Xcode compilation cache are complementary. A Tuist hit replaces the complete target before compilation. On a Tuist miss, Xcode builds the target from source and can reuse lower-level compiler outputs for eligible project source. Targets that Tuist cannot store, including the application target, can still benefit from Xcode compilation caching. Xcode 26 does not cache Swift package dependencies embedded in an application-target build; see Xcode Compilation Cache.

tuist install uses the GitHub Actions and Swift registry layers, not the two compilation caches. tuist cache warm builds missing targets through Xcode, so eligible compilation work can also reuse the Xcode compilation cache.

An image, Xcode, or Tuist upgrade can change target hashes. A temporary miss spike and cache re-warm are expected after those rollouts.

Tuist entries appear with type tuist-module-build on the Caches page and in avr cache output. Xcode entries appear as xcode-build. Both are isolated to the Avrea repository, count toward its cache quota, and follow normal cache eviction.

Confirm that Tuist Module Cache is enabled for the organization or repository, then start a new macOS job. A repository-level override takes precedence over the organization setting.

  • Warm the cache before expecting a download on a fresh runner.
  • Keep fullHandle stable across jobs.
  • Use the same repository and compatible runner image for warm and build jobs.
  • Check for absolute paths, timestamps, or other non-deterministic inputs in the target hash.
  • Confirm that the branch being built contains the active fullHandle.
  • Run tuist cache warm; normal generation consumes warmed artifacts but does not populate an empty remote cache.
  • Do not pass --no-upload, and confirm that the selected cache profile contains eligible targets.

Use a focused tuist generate, confirm the target product is cacheable, and check that its dependency graph does not contain an uncacheable target. Tuist can identify implicit dependencies with:

Terminal window
tuist inspect dependencies --only implicit

SwiftPM reports that no registry is configured for a scope

Section titled “SwiftPM reports that no registry is configured for a scope”

Avrea's managed default registry handles public scopes without workflow configuration. Check whether the workflow or runner image creates its own SwiftPM registries.json, which takes precedence over the managed configuration. Remove the custom file or follow the custom registry configuration guidance.