Inconsistent transitive dependency version when WORKSPACE and MODULE.bazel coexist
0 reputation · 18 Oct 2023, 07:15 UTC
0 reputation · 18 Oct 2023, 07:15 UTC
Ensure that a Bazel build produces identical external dependency graphs across developer machines when a project contains both a WORKSPACE file and a MODULE.bazel file during the migration to Bzlmod.
The effective version of a transitive dependency may differ depending on the Bazel release, the presence of local override files, or whether the experimental Bzlmod flag is enabled, leading to non‑repeatable builds across teams.
Which file takes precedence when both are present? Does enabling the --experimental_bzlmod flag alter this precedence? Are there specific .bazelrc settings that force consistent resolution?
31775 reputation · 18 Oct 2023, 17:11 UTC
When both files exist, exactly one of them governs external dependency resolution, and the deciding factor is whether Bzlmod is enabled — not the presence of the files themselves.
WORKSPACE file wins. MODULE.bazel is ignored for external dependencies.--enable_bzlmod, or by default on Bazel 7+): MODULE.bazel and its lockfile win, and WORKSPACE is ignored for module resolution.So the flag does not merely tweak behavior — it flips precedence entirely. Non-repeatable builds across a team almost always trace back to developers landing on different sides of that switch.
Three independent variables decide which graph you get:
.bazelrc files. A user-level ~/.bazelrc or an uncommitted .bazelrc can enable or disable Bzlmod for one developer only.--override_repository, --override_module, and local path overrides can shift resolved versions even when precedence is consistent.Pin the mode in the project-level .bazelrc (committed to version control), and pin the Bazel version with .bazelversion so Bazelisk enforces it:
# .bazelrc — pick ONE mode for the whole team
common --enable_bzlmod
# .bazelversion
7.4.1Then commit MODULE.bazel.lock so the resolved transitive graph is shared, and audit for stray overrides:
bazel info release
grep -r "override" .bazelrc ~/.bazelrc 2>/dev/null
bazel mod graph | head -50bazel mod graph shows the effective resolved module versions and is the quickest way to confirm two machines agree.
To confirm which file is authoritative in your setup, declare the same dependency at different versions in each file, then build with and without the flag:
bazel info release
bazel mod graph # fails or is irrelevant when Bzlmod is off
bazel --enable_bzlmod mod graph # shows MODULE.bazel's versionIf the resolved version changes when you toggle the flag, precedence is working as described, and your team's inconsistency is a configuration drift problem, not a Bazel bug.
This describes well-established behavior for Bazel 6.x/7.x; exact flag names (--experimental_bzlmod vs --enable_bzlmod) vary by release, so check bazel help build on your version. If any legacy rules still expect WORKSPACE-defined repositories, removing the WORKSPACE file outright can break the build — migrate dependencies into MODULE.bazel first. One missing detail that would change this advice: your exact Bazel version, since defaults differ across the 6/7 boundary.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.