What
Per-run module cache network analytics: for every run, see how much data the module (binary) cache moved and how fast, right next to its hit rate.

On a run’s Module Cache tab:
- Downloaded / Uploaded (Summary card) — total bytes of prebuilt modules the run pulled from and pushed to the remote cache.
- Download / Upload throughput (Module Cache card) — time-weighted average transfer speed, matching the Xcode Cache (CAS Outputs) layout.
Why
Hit rate tells you how many modules you skipped rebuilding; it doesn’t tell you what the cache cost over the wire. When evaluating or optimizing the module cache (especially on CI), the artifact fetch is usually the remaining lever: a slow or partial remote fetch shows up as a run-to-run outlier. These numbers make the network side visible per run, so a slow-fetch run points at itself.
How it works
- The CLI reports per-artifact transfers (operation, size, compressed size, duration) on the command event as
module_cache_transfers. The remote-cache-storage instrumentation that records them lives in TuistCacheEE (companion PR: tuist/TuistCacheEE#68).
- The server ingests them into a
module_cache_outputs ClickHouse table keyed by command_event_id. It can’t reuse cas_outputs (build-run-scoped): the module cache is fetched during tuist generate, before any build run exists. This mirrors how cas_outputs ride the POST /builds payload: the same flat per-artifact list, attached to whichever run entity exists for that command.
CommandEvents.module_cache_transfer_summary/1 derives download/upload counts, bytes, and time-weighted throughput per run, a direct analog of Tuist.Builds.cas_output_metrics/1.
- Surfaced on the run detail Module Cache tab (a shared component, so it reaches build and test runs too).
Scope note
An earlier iteration explored aggregate transfer/latency/throughput/fetch-time widgets on the Module Cache overview page; that was removed in favor of the per-run view above (the overview is back to hit-rate/hits/misses), and overall fetch-time tracking was dropped entirely. See the PR comments for the full evolution.
Validation
- Server compiles clean;
mix format + Credo consistent; OpenAPI client regenerated.
- Tests for the ingest path and
module_cache_transfer_summary/1 (counts, bytes, and throughput).
- Verified end-to-end on a local instance: the run detail Module Cache tab renders the Summary and throughput widgets from seeded
module_cache_outputs data (screenshot above).
Companion
- TuistCacheEE instrumentation: tuist/TuistCacheEE#68. It must land together, since it fills the
ModuleCacheTransfer sink the server reads from.
🤖 Generated with Claude Code