Advanced Elixir cache configuration
Start with the Elixir cache setup guide. The options below are only needed when your project has additional compilation inputs, dependency exceptions or different checkout paths.
Select dependencies#
cache: true caches supported dependencies automatically. A keyword list has the
same automatic selection, with optional overrides:
cache: [exclude: [:a_dependency_with_compile_time_side_effects]]
To limit caching to specific dependencies instead:
cache: [dependencies: [:nimble_options, :nimble_parsec]]
dependencies: :all explicitly selects all supported dependencies;
dependencies: [] selects none. exclude: takes precedence over either selection.
Omitting cache, or setting it to false or nil, disables caching.
Supported dependencies are fetched through Hex or Git and use the standard Mix compiler pipeline with pure Elixir sources. Native/custom compilers, custom tracers, source symlinks, umbrella roots and chains containing local dependencies compile normally. Tuist's own bootstrap dependencies also compile normally. Structural eligibility does not prove that arbitrary compilation code is hermetic.
Declare additional inputs#
Source trees, locked dependency identities, upstream sources and BEAMs,
explicit effective application configuration, compiler options, Mix environment
and target, and toolchain identity are included automatically. Dependency-specific
env: and system_env: enter the key and configuration is evaluated under that
environment. Application defaults enter through source inputs, not VM loading state.
For dependencies that read files outside their source tree or additional environment variables at compile time, declare those inputs:
cache: [
inputs: ["schemas", "config/compiler-input.json"],
env: ["YOUR_COMPILER_OPTION"]
]
Elixir macros and module bodies can read arbitrary files, environment, ambient
code paths, network responses and time. Tuist does not automatically discover
these reads. Changing undeclared inputs can produce stale outputs. Exclude
dependencies with time/network-dependent compilation or side effects that must
execute on every build; use dependencies: for an audited dependency allowlist
when you need tighter control.
Standard compiler/runtime variables (ERL_COMPILER_OPTIONS, ELIXIR_ERL_OPTIONS,
ERL_AFLAGS, ERL_FLAGS, ERL_ZFLAGS, SOURCE_DATE_EPOCH, ERL_LIBS, MIX_PATH
and MIX_ARCHIVES) are captured automatically. Toolchain identity includes the
Elixir build, full OTP version when available, ERTS, compiler bytecode, OS/version,
architecture, word size and byte order. Inputs are captured before each lookup
and checked again before publication, including changes from earlier compilations.
Reuse across checkout paths#
Checkout paths participate in keys by default. If your dependencies don't rely on producer paths, opt into reuse between different checkout locations:
cache: [portable: true]
Cached BEAMs retain producer debug/source paths and compile-time __DIR__,
__ENV__.file and File.cwd!() values. Portable reuse does not rewrite them.
Resource links point to the current source checkout. Upstream BEAM bytes also
enter keys and may embed paths, so reuse can require restoring the upstream
closure from the same cache rather than recompiling it independently.
Storage and access#
| Option | Default | Purpose |
|---|---|---|
remote | true | Use the shared remote cache after a local miss. |
upload | true | Publish new bundles remotely. false still allows reads and local snapshots. |
path | Tuist's cache directory, under mix/dependencies/v1 | Choose a different local store. |
endpoint | Discovered automatically | Override the account's HTTPS REAPI endpoint. |
upload: false controls client behavior, not authorization. Project cache
permissions are enforced by the server. HTTP is only allowed on loopback
(localhost, 127.0.0.1, ::1) for development and sends credentials/artifacts
unencrypted. Local snapshots and remote bundles are limited to 64 MiB; larger
artifacts compile without being cached. The local store has no automatic eviction;
remove its contents when needed. Remote artifacts use Kura's existing retention,
eviction and project-cleanup rules.
Compiler manifests and BEAMs can embed producer paths and compile-time values, including secrets. Project cache readers can access those artifacts. Cache writers are trusted code producers: digest checks detect corruption, not malicious executable BEAMs. Don't expose cache-write credentials to untrusted PR jobs or compile untrusted dependencies with those credentials available.
Troubleshoot missing hits#
- Run
mix tuist.setupafter installing the package and commit the generated Mix configuration. Setup preserves other aliases and Tuist options; it refuses customized compile actions rather than silently removing them. - Keep the generated compile alias. Direct
mix tuist.compiletask discovery can compile dependencies before caching can inspect them. - Already-current outputs aren't cache hits and aren't published retrospectively.
Clean just a supported dependency's build with
mix deps.clean NAME --buildafter it has populated the cache, then compile again. - Match
MIX_ENV,MIX_TARGET, compiler settings and declared inputs. Path changes also change keys unless portable reuse is enabled. - Unsupported dependencies appear as Not cached, not misses. They are excluded from hit rate. A build with no lookups has an unavailable rate, not 0%.
- Missing credentials, unavailable endpoints and corrupt snapshots fall back to compilation. Compiler failures still fail the build.
- CAS records can arrive after the build report. Refresh to see newly ingested transfers. Local hits and legacy builds have no remote CAS outputs.
Manual compile integration#
If setup cannot edit your project's configuration safely, integrate this alias manually, preserving any custom compile actions:
compile: [
"deps.compile tuist_ex --include-children",
"deps.loadpaths --no-compile --no-deps-check",
"tuist.compile"
]
These steps compile and load Tuist before other dependencies, including on cold parallel builds. The wrapper restores normal dependency checks afterward. The same alias works with Hex, Git and path installations; no script path is needed.
How it works#
Elixir caching uses the shared REAPI ActionCache/CAS pipeline, authentication and Kura-signed analytics used by Bazel, not a separate Mix storage service. A modeled input key references an ActionResult containing the raw-byte SHA-256 digest of a complete compilation bundle. Tuist verifies its files, application metadata, declared BEAMs and SCM manifest before staged installation. Corrupt entries are repaired after successful compilation.
Remote credentials/connections are resolved lazily; idle builds and local hits don't contact remote endpoints. One session is closed on every exit, including compiler failure. Client RPCs have a 30-second deadline. Mix remains responsible for lock checks, local dependency compilation and unsupported work.
Dashboard latency/bytes preserve local versus remote provenance and distinguish unavailable values from measured zero. Remote timing measures client CAS transfers, while local timing includes verification and installation; neither includes compilation. CAS Outputs uses successful Kura-signed transfers, not local copies or action-input keys. Throughput is bytes divided by measured time; compressed sizes are unavailable. Estimated compilation time avoided is the producer's original compile duration, not measured end-to-end build savings.