--disk_cache, --remote_cache, --repository_cache, --jobs), and Git shallow clone coordination notes. Pair with the blog index, cross-border mirror CI guide, and build pool disk FAQ—public pages, no login wall.
- Registry fan-out: Bazel modules hit the Bazel Central Registry and GitHub tarballs; one flaky hop stalls analysis before your first compile action runs.
- Cache collision: many jobs append to the same
--disk_cachepath while downloading into--repository_cacheon one SSD—latency spikes look like “slow Bazel” but are queue depth. - Git depth mismatch: CI uses
git clone --depth 1for the app repo while agit_repositoryor vendor script expects tags outside the shallow window.
① Bazel externals and registry bottlenecks on a remote Mac
On Apple Silicon CI hosts, the expensive phase is rarely the first compiler invocation—it is repository resolution. WORKSPACE-style rules (http_archive, git_repository, custom macros) download archives and Git objects over HTTPS. Bzlmod paths resolve through the module registry, which still ends on tarball and Git providers. Cross-border links add RTT variance, middlebox TLS inspection, and occasional reset-by-peer bursts that surface as “repository failed” rather than compile errors.
Disk enters the picture twice: the repository cache stores immutable downloads keyed by content, while extracted trees land under $(bazel info output_base)/external. If output_base sits on the same volume as a hot --disk_cache, parallel analyses from multiple CI jobs interleave random writes from action outputs with sequential-ish unpack patterns from externals. Treat network and IO as one system: when registry latency is good but builds jitter, inspect per-volume throughput before raising --jobs.
Related: Git and Docker pull acceleration for transport-layer patterns that also help Bazel’s HTTP fetches, and remote Mac build node guide for SSH-first layout of workspaces and caches.
② Local disk_cache versus remote_cache: selection thresholds
Use the table before you buy hardware or enable a shared endpoint. --disk_cache stores action output blobs locally; --remote_cache (gRPC or HTTP) shares action outputs across machines. --repository_cache is the third leg—it deduplicates upstream downloads and is usually the highest ROI for cross-border CI.
| Signal you measure | Prefer local --disk_cache |
Prefer --remote_cache |
Notes |
|---|---|---|---|
| Number of concurrent CI jobs on one host | 1–2 jobs; predictable reuse window | 3+ jobs or ephemeral workspaces wiped each run | Remote cache shifts action output reuse off local SSD; still keep --repository_cache local when egress is costly |
Hit rate after cold bazel clean --expunge |
High when the same user or pool rebuilds one mono-repo daily | High when many repos share toolchains and genrules | Namespace caches per trust boundary; do not mix regulated artifacts with public repos without policy review |
| Egress cost / cross-border stability | Acceptable when mirrors sit near the runner region | Strong when the cache endpoint is co-located with runners | A remote cache in another continent can hurt more than it helps—tune --remote_timeout and download modes |
| Operational burden | Low; path plus janitor script | Higher; TLS, auth headers, quotas | Hybrid pattern: --repository_cache + --disk_cache locally, --remote_cache for action outputs only |
Concurrency knob: --jobs=N scales local actions. On fetch-heavy builds, high N before the repository cache warms increases simultaneous unpacks and competes with disk cache writers—start conservative, watch IO wait, then step up.
③ WORKSPACE / MODULE fetch retries, timeouts, and cache flags
Pin these in checked-in .bazelrc or generated CI rc fragments. Adjust paths and secrets; never paste live tokens into public repos—inject --remote_header values from the orchestrator.
| Flag or setting | Purpose | Example / starting point |
|---|---|---|
common --repository_cache=… |
Reuse downloaded externals across workspaces | /usr/local/ci/bazel-repo-cache on NVMe |
build --disk_cache=… |
Local action output cache | /usr/local/ci/bazel-disk-cache per pool |
build --remote_cache=… |
Shared action cache (gRPC/HTTP) | grpcs://cache.example:443 |
build --remote_header |
Auth for remote cache / proxy | Authorization=Bearer $(CACHE_TOKEN) via env expansion in CI |
build --remote_timeout |
Longer uploads on slow uplinks | 600 seconds as a first trial for large blobs |
common --experimental_repository_downloader_retries |
Retry flaky repository HTTP downloads | 5 after validating Bazel release notes for your minor version |
build --jobs |
Local action parallelism | Half of performance cores when disk and repo cache share one volume; raise when IO wait stays low |
| MODULE mirrors (enterprise) | Override default registry URLs | --registry=file:///… or mirrored index—keep in sync with security review |
Illustrative fragment—split across profiles in real pipelines:
# Shared CI prelude (paths are examples)
common --repository_cache=/usr/local/ci/bazel-repo-cache
common --experimental_repository_downloader_retries=5
build --disk_cache=/usr/local/ci/bazel-disk-cache
build --remote_cache=grpcs://bazel-cache.internal.example:443
build --remote_timeout=600
# build --remote_header=Authorization=Bearer ${BAZEL_CACHE_TOKEN}
Validate with a single warm-up job: bazel fetch //… or an analysis-only target, then enable matrix fan-out. Surface failures in CI logs with --verbose_failures during the first rollout week.
④ Git partial clones, directories, and IO quotas (FAQ)
Yes for the checked-out project when commit SHAs are fully reachable at the declared depth. Keep Bazel’s external Git roots on immutable SHAs in WORKSPACE or module patches. If a rule needs tags outside the shallow set, increase depth for that clone step or vendor the archive with http_archive and checksum.
--repository_cache share a volume with --disk_cache?
Physically yes, but budget IOPS. Splitting across two fast volumes reduces tail latency when analysis, fetch, and compile overlap. Leave at least 15–20% free space on each cache volume so APFS does not throttle during CI peaks.
--disk_cache folder?
Read-heavy phases are usually safe; pruning jobs or aggressive cleaners racing writers cause sporadic corruption messages. Prefer remote cache for multi-tenant hosts or use per-pool subdirectories and serialized maintenance windows.
Align timestamps from Bazel’s repository log with host disk metrics. High queue depth with normal ping to the registry implicates disk; idle disk with TLS handshake stalls implicates egress or DNS—match fixes to SSH relay and proxy patterns where applicable.
⑤ Remote Mac region and parallel compile impact on fetch stability
Place the runner close to the registries and mirrors you actually use. A remote Mac in region A with a remote cache in region B may save compile time yet lose those gains to upload/download phases, especially for large intermediate artifacts. Co-locate the cache endpoint, artifact storage, and runner when cross-border links are lossy.
Parallel compiles amplify the issue: high --jobs increases local CPU and disk pressure while repository rules may still stream downloads. Stagger matrix legs, cap simultaneous Bazel invocations per host, or dedicate one “fetch” job that populates --repository_cache before fan-out. This pattern mirrors the queueing advice in the concurrent pull and disk FAQ—treat Bazel as another heavy consumer of the same IO budget.
Rollout checklist: five executable steps
mkdir -p for repository and disk caches; set owner to the CI user; exclude them from Time Machine if backups slow disks.common lines for --repository_cache and retries; add build lines for --disk_cache and optional --remote_cache with timeouts.--jobs. Benchmark one representative target at N = cores/2, then raise while monitoring disk latency.bazel fetch step on fresh images.Summary
Bazel on remote Mac CI fails loudly in the fetch layer: tune --repository_cache first for cross-border stability, add --disk_cache or --remote_cache based on host count and reuse, and cap --jobs against real disk throughput. Pair immutable Git SHAs with shallow clones consciously, and keep cache endpoints in the same region as your runners when WAN is the bottleneck.
When you are ready to offload fetch-heavy builds to dedicated Apple Silicon, start at the homepage, compare pricing, and complete purchase or rental in a few clicks. Use the help center for provisioning questions, browse the technical blog for more CI playbooks, and revisit remote Mac build node setup for SSH-oriented workflows—no login required to read these pages.
Next reads: Gradle and Maven cache matrix for polyglot repos, and Go GOPROXY matrix when services mix languages under one pipeline.
Remote Mac for Bazel CI and cache-heavy builds
Dedicated Apple Silicon nodes, fast SSD layouts for repository and disk caches, and SSH-friendly debugging. Open pricing, purchase, help, or the blog without signing in.