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.
Enable the cache
Section titled “Enable the cache”Turn on Tuist Module Cache at the organization or repository level under Settings in the Avrea console. You can also use the CLI:
avr settings set cache.tuist-module.enabled trueThe 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.
Configure the project
Section titled “Configure the 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.
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.
On Avrea runners
Section titled “On Avrea runners”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.
Warm the cache from the main branch
Section titled “Warm the cache from the main branch”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.
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 warmKeep 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.
Consume the cache in pull requests
Section titled “Consume the cache in pull requests”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.
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 testAdapt 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.
Optional: accelerate package installation
Section titled “Optional: accelerate package installation”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:
- 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-versionsThis 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.
How the cache layers work together
Section titled “How the cache layers work together”Each layer avoids a different kind of work:
| Layer | What it stores | When it is used | Isolation | Avrea storage |
|---|---|---|---|---|
| GitHub Actions cache | Tuist/.build and Tuist/Package.resolved dependency state | Restores installed dependencies before tuist install | Repository-scoped, subject to GitHub branch and ref visibility rules | Private GitHub Actions cache |
| Swift package registry | Package source archives, manifests, versions, and checksums | Supplies eligible semantic-version public and private packages during tuist install | Public packages are shared; private packages are organization-isolated | Public package storage or private artifact storage |
| Tuist module cache | Complete prebuilt binaries for eligible project and dependency targets | Substitutes an entire target during project generation and builds | Repository-isolated | Private tuist-module-build cache |
| Xcode compilation cache | Reusable compiler outputs for project source and directly built packages | Speeds up eligible source compilation when a complete Tuist module is unavailable | Repository-isolated | Private 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.
Troubleshooting
Section titled “Troubleshooting”The environment variables are missing
Section titled “The environment variables are missing”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.
Every run is a miss
Section titled “Every run is a miss”- Warm the cache before expecting a download on a fresh runner.
- Keep
fullHandlestable 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.
No artifacts are uploaded
Section titled “No artifacts are uploaded”- 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.
A target is not substituted
Section titled “A target is not substituted”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:
tuist inspect dependencies --only implicitSwiftPM 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.