PATTERN Cited by 1 source
Build without the bytes (BwoB)¶
Skip downloading cached action outputs to the client unless a
downstream local action actually needs them; keep just the
content-addressed digest. Bazel exposes this as
--remote-download-minimal. Canva's adoption turned this flag —
plus a trivial retry-on-cache-eviction shim — into a 2–3× lever
on Bazel-step wall-clock (Source: sources/2024-12-16-canva-faster-ci-builds).
Intent¶
When CI workers share a content-addressed cache
(e.g. bazel-remote backed by S3), a Bazel build's cache hit normally
downloads the resulting artifact to the worker. For container images,
test fixtures, or large native binaries, this round-trip dominates
wall-clock — the client has the bytes on disk only to upload them right
back out to the next action that needs them, or to discard them if
nothing downstream runs locally. BwoB breaks this pattern: the client
records the digest in the local in-memory graph and only fetches the
actual bytes if a local action has the artifact as an input.
Mechanism¶
- Cache hit → digest, not bytes. Bazel with
--remote-download-minimalrecords the action's output digest from the remote cache without downloading the blob. - Local-action trigger pulls the bytes. If a subsequent action on the same worker needs the artifact as an input, Bazel fetches it on demand.
- Test action orchestration unchanged. Tests still see their inputs because Bazel fetches them when a local test action fires.
The correctness property: same build result as without the flag, because the graph's behaviour only depends on whether actions had their inputs available when they ran — not on whether cached outputs were prefetched.
Canva's numbers¶
| Build type | Before | After | Speed-up |
|---|---|---|---|
| Backend | ~10 min | ~5 min | 2× |
| Machine learning | ~6 min | <2 min | 3.3× |
Adopted on all Bazel steps (builds and tests) after the rollout.
The cache-eviction hazard¶
BwoB's only failure mode: if the remote cache evicts an artifact that the local action set defers fetching until later, the later fetch returns "not found" and the build errors. (Bazel issue #10880).
Canva's fix: retry the build on that specific failure. Evictions are rare enough that retry-on-eviction costs far less than the BwoB savings:
After learning of this cache issue, we experimented with a simple workaround of retrying when those (fairly rare) cache check failures occur. It worked really well and we rolled it out.
A real-world example of "the cheap workaround beats the thorough fix" when the failure mode is rare and detection is trivial.
Preconditions¶
- A shared remote cache. BwoB is a BUY-side pattern; if your cache is local-only, there's nothing to not download.
- Hermetic actions. Without hermeticity, cache keys aren't reliable and BwoB amplifies any keying bug into a correctness incident.
- Rare cache eviction. If your cache's GC is aggressive, the retry shim's cost climbs.
Composability¶
BwoB + RBE is the full "thin client" story: RBE workers share a local CAS, so even between RBE workers the artifacts don't flow over the client network. BwoB is RBE's natural successor for teams that haven't fully migrated to RBE yet.
Related¶
- concepts/content-addressed-caching — the substrate.
- concepts/hermetic-build — the correctness precondition.
- concepts/critical-path — what BwoB shortens.
- concepts/remote-build-execution — the full thin-client evolution.
- systems/bazel — flag exposed here.
- systems/bazel-remote — what the BwoB client talks to.
Seen in¶
- sources/2024-12-16-canva-faster-ci-builds — 2× backend, 3.3× ML; retry-on-cache-eviction workaround rolled out fleet-wide.