| --- | |
| title: 'Frequently asked questions' | |
| --- | |
| This page answers some frequently asked questions about external dependencies in | |
| Bazel. | |
| ## MODULE.bazel {#module-bazel} | |
| ### How should I version a Bazel module? {#module-versioning-best-practices} | |
| Setting `version` with the [`module`] directive in the source archive | |
| `MODULE.bazel` can have several downsides and unintended side effects if not | |
| managed carefully: | |
| * Duplication: releasing a new version of a module typically involves both | |
| incrementing the version in `MODULE.bazel` and tagging the release, two | |
| separate steps that can fall out of sync. While automation can | |
| reduce this risk, it's simpler and safer to avoid it altogether. | |
| * Inconsistency: users overriding a module with a specific commit using a | |
| [non-registry override] will see an incorrect version. for example, if the | |
| `MODULE.bazel` in the source archive sets `version = "0.3.0"` but | |
| additional commits have been made since that release, a user overriding | |
| with one of those commits would still see `0.3.0`. In reality, the version | |
| should reflect that it's ahead of the release, for example `0.3.1-rc1`. | |
| * Non-registry override issues: using placeholder values can cause issues | |
| when users override a module with a non-registry override. For example, | |
| `0.0.0` doesn't sort as the highest version, which is usually the expected | |
| behavior users want when doing a non-registry override. | |
| Thus, it's best to avoid setting the version in the source archive | |
| `MODULE.bazel`. Instead, set it in the `MODULE.bazel` stored in the registry | |
| (e.g., the [Bazel Central Registry]), which is the actual source of truth for | |
| the module version during Bazel's external dependency resolution (see [Bazel | |
| registries]). | |
| This is usually automated, for example the [`rules-template`] example rule | |
| repository uses a [bazel-contrib/publish-to-bcr publish.yaml GitHub Action] to | |
| publish the release to the BCR. The action [generates a patch for the source | |
| archive `MODULE.bazel`] with the release version. This patch is stored in the | |
| registry and is applied when the module is fetched during Bazel's external | |
| dependency resolution. | |
| This way, the version in the releases in the registry will be correctly set to | |
| the released version and thus, `bazel_dep`, `single_version_override` and | |
| `multiple_version_override` will work as expected, while avoiding potential | |
| issues when doing a non-registry override because the version in the source | |
| archive will be the default value (`''`), which will always be handled | |
| correctly (it's the default version value after all) and will behave as | |
| expected when sorting (the empty string is treated as the highest version). | |
| [Bazel Central Registry]: https://registry.bazel.build/ | |
| [Bazel registries]: https://bazel.build/external/registry | |
| [bazel-contrib/publish-to-bcr publish.yaml GitHub Action]: https://github.com/bazel-contrib/publish-to-bcr/blob/v0.2.2/.github/workflows/publish.yaml | |
| [generates a patch for the source archive `MODULE.bazel`]: https://github.com/bazel-contrib/publish-to-bcr/blob/v0.2.2/src/domain/create-entry.ts#L176-L216 | |
| [`module`]: /rules/lib/globals/module#module | |
| [non-registry override]: module.md#non-registry_overrides | |
| [`rules-template`]: https://github.com/bazel-contrib/rules-template | |
| ### What is a compatibility level? | |
| You should stop using `compatibility_level`. | |
| Increasing `compatibility_level` leads to version conflicts that are difficult | |
| for end users to resolve. Therefore, starting with Bazel 8.6.0 and 9.1.0, both | |
| `compatibility_level` and `max_compatibility_level` are no-ops. | |
| Module maintainers introducing major breaking changes should ensure that build | |
| failures provide clear error messages and actionable migration paths. | |
| **Legacy documentation:** | |
| The [`compatibility_level`](module.md#compatibility_level) of a Bazel module | |
| should be incremented _in the same commit_ that introduces a backwards | |
| incompatible ("breaking") change. | |
| However, Bazel can throw an error if it detects that versions of the _same | |
| module_ with _different compatibility levels_ exist in the resolved dependency | |
| graph. This can happen when for example' two modules depend on versions of a | |
| third module with different compatibility levels. | |
| Thus, incrementing `compatibility_level` too frequently can be very disruptive | |
| and is discouraged. To avoid this situation, the `compatibility_level` should be | |
| incremented _only_ when the breaking change affects most use cases and isn't | |
| easy to migrate and/or work-around. | |
| ### Why does MODULE.bazel not support `load`s? {#why-does-module-bazel-not-support-loads} | |
| During dependency resolution, the MODULE.bazel file of all referenced external | |
| dependencies are fetched from registries. At this stage, the source archives of | |
| the dependencies are not fetched yet; so if the MODULE.bazel file `load`s | |
| another file, there is no way for Bazel to actually fetch that file without | |
| fetching the entire source archive. Note the MODULE.bazel file itself is | |
| special, as it's directly hosted on the registry. | |
| There are a few use cases that people asking for `load`s in MODULE.bazel are | |
| generally interested in, and they can be solved without `load`s: | |
| * Ensuring that the version listed in MODULE.bazel is consistent with build | |
| metadata stored elsewhere, for example in a .bzl file: This can be achieved | |
| by using the | |
| [`native.module_version`](/versions/9.3.0/rules/lib/toplevel/native#module_version) method | |
| in a .bzl file loaded from a BUILD file. | |
| * Splitting up a very large MODULE.bazel file into manageable sections, | |
| particularly for monorepos: The root module can use the | |
| [`include`](/versions/9.3.0/rules/lib/globals/module#include) directive to split its | |
| MODULE.bazel file into multiple segments. For the same reason we don't allow | |
| `load`s in MODULE.bazel files, `include` cannot be used in non-root modules. | |
| * Users of the old WORKSPACE system might remember declaring a repo, and then | |
| immediately `load`ing from that repo to perform complex logic. This | |
| capability has been replaced by [module extensions](extension). | |
| ### Can I specify a SemVer range for a `bazel_dep`? {#can-i-specify-a-semver-range-for-a-bazel-dep} | |
| No. Some other package managers like [npm][npm-semver] and [Cargo][cargo-semver] | |
| support version ranges (implicitly or explicitly), and this often requires a | |
| constraint solver (making the output harder to predict for users) and makes | |
| version resolution nonreproducible without a lockfile. | |
| Bazel instead uses [Minimal Version Selection](module#version-selection) like | |
| Go, which in contrast makes the output easy to predict and guarantees | |
| reproducibility. This is a tradeoff that matches Bazel's design goals. | |
| Furthermore, Bazel module versions are [a superset of | |
| SemVer](module#version-format), so what makes sense in a strict SemVer | |
| environment doesn't always carry over to Bazel module versions. | |
| ### Can I automatically get the latest version for a `bazel_dep`? {#can-i-automatically-get-the-latest-version-for-a-bazel-dep} | |
| Some users occasionally ask for the ability to specify `bazel_dep(name = "foo", | |
| version = "latest")` to automatically get the latest version of a dep. This is | |
| similar to [the question about SemVer | |
| ranges](#can-i-specify-a-semver-range-for-a-bazel-dep), and the answer is also | |
| no. | |
| The recommended solution here is to have automation take care of this. For | |
| example, [Renovate](https://docs.renovatebot.com/modules/manager/) supports | |
| Bazel modules. | |
| Sometimes, users asking this question are really looking for a way to quickly | |
| iterate during local development. This can be achieved by using a | |
| [`local_path_override`](/versions/9.3.0/rules/lib/globals/module#local_path_override). | |
| ### Why all these `use_repo`s? {#why-all-these-use-repos} | |
| Module extension usages in MODULE.bazel files sometimes come with a big | |
| `use_repo` directive. For example, a typical usage of the | |
| [`go_deps` extension][go_deps] from `gazelle` might look like: | |
| ```python | |
| go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") | |
| go_deps.from_file(go_mod = "//:go.mod") | |
| use_repo( | |
| go_deps, | |
| "com_github_gogo_protobuf", | |
| "com_github_golang_mock", | |
| "com_github_golang_protobuf", | |
| "org_golang_x_net", | |
| ... # potentially dozens of lines... | |
| ) | |
| ``` | |
| The long `use_repo` directive may seem redundant, since the information is | |
| arguably already in the referenced `go.mod` file. | |
| The reason Bazel needs this `use_repo` directive is that it runs module | |
| extensions lazily. That is, a module extension is only run if its result is | |
| observed. Since a module extension's "output" is repo definitions, this means | |
| that we only run a module extension if a repo it defines is requested (for | |
| instance, if the target `@org_golang_x_net//:foo` is built, in the example | |
| above). However, we don't know which repos a module extension would define until | |
| after we run it. This is where the `use_repo` directive comes in; the user can | |
| tell Bazel which repos they expect the extension to generate, and Bazel would | |
| then only run the extension when these specific repos are used. | |
| To help the maintain this `use_repo` directive, a module extension can return | |
| an [`extension_metadata`](/versions/9.3.0/rules/lib/builtins/module_ctx#extension_metadata) | |
| object from its implementation function. The user can run the `bazel mod tidy` | |
| command to update the `use_repo` directives for these module extensions. | |
| ## Bzlmod migration {#bzlmod-migration} | |
| ### Which is evaluated first, MODULE.bazel or WORKSPACE? {#which-is-evaluated-first-module-bazel-or-workspace} | |
| When both `--enable_bzlmod` and `--enable_workspace` are set, it's natural to | |
| wonder which system is consulted first. The short answer is that MODULE.bazel | |
| (Bzlmod) is evaluated first. | |
| The long answer is that "which evaluates first" is not the right question to | |
| ask; rather, the right question to ask is: in the context of the repo with | |
| [canonical name](overview#canonical-repo-name) `@@foo`, what does the [apparent | |
| repo name](overview#apparent-repo-name) `@bar` resolve to? Alternatively, what | |
| is the repo mapping of `@@base`? | |
| Labels with apparent repo names (a single leading `@`) can refer to different | |
| things based on the context they're resolved from. When you see a label | |
| `@bar//:baz` and wonder what it actually points to, you need to first find out | |
| what the context repo is: for example, if the label is in a BUILD file located | |
| in the repo `@@foo`, then the context repo is `@@foo`. | |
| Then, depending on what the context repo is, the ["repository | |
| visibility" table](migration#repository-visibility) in the migration guide can | |
| be used to find out which repo an apparent name actually resolves to. | |
| * If the context repo is the main repo (`@@`): | |
| 1. If `bar` is an apparent repo name introduced by the root module's | |
| MODULE.bazel file (through any of | |
| [`bazel_dep`](/versions/9.3.0/rules/lib/globals/module#bazel_dep.repo_name), | |
| [`use_repo`](/versions/9.3.0/rules/lib/globals/module#use_repo), | |
| [`module`](/versions/9.3.0/rules/lib/globals/module#module.repo_name), | |
| [`use_repo_rule`](/versions/9.3.0/rules/lib/globals/module#use_repo_rule)), then `@bar` | |
| resolves to what that MODULE.bazel file claims. | |
| 2. Otherwise, if `bar` is a repo defined in WORKSPACE (which means that its | |
| canonical name is `@@bar`), then `@bar` resolves to `@@bar`. | |
| 3. Otherwise, `@bar` resolves to something like | |
| `@@[unknown repo 'bar' requested from @@]`, and this will ultimately | |
| result in an error. | |
| * If the context repo is a Bzlmod-world repo (that is, it corresponds to a | |
| non-root Bazel module, or is generated by a module extension), then it | |
| will only ever see other Bzlmod-world repos, and no WORKSPACE-world repos. | |
| * Notably, this includes any repos introduced in a `non_module_deps`-like | |
| module extension in the root module, or `use_repo_rule` instantiations | |
| in the root module. | |
| * If the context repo is defined in WORKSPACE: | |
| 1. First, check if the context repo definition has the magical | |
| `repo_mapping` attribute. If so, go through the mapping first (so for a | |
| repo defined with `repo_mapping = {"@bar": "@baz"}`, we would be looking | |
| at `@baz` below). | |
| 2. If `bar` is an apparent repo name introduced by the root module's | |
| MODULE.bazel file, then `@bar` resolves to what that MODULE.bazel file | |
| claims. (This is the same as item 1 in the main repo case.) | |
| 3. Otherwise, `@bar` resolves to `@@bar`. This most likely will point to a | |
| repo `bar` defined in WORKSPACE; if such a repo is not defined, Bazel | |
| will throw an error. | |
| For a more succinct version: | |
| * Bzlmod-world repos (excluding the main repo) will only see Bzlmod-world | |
| repos. | |
| * WORKSPACE-world repos (including the main repo) will first see what the root | |
| module in the Bzlmod world defines, then fall back to seeing WORKSPACE-world | |
| repos. | |
| Of note, labels in the Bazel command line (including Starlark flags, label-typed | |
| flag values, and build/test target patterns) are treated as having the main repo | |
| as the context repo. | |
| ## Other {#other} | |
| ### How do I prepare and run an offline build? {#how-do-i-prepare-and-run-an-offline-build} | |
| Use the `bazel fetch` command to prefetch repos. You can use the `--repo` flag | |
| (like `bazel fetch --repo @foo`) to fetch only the repo `@foo` (resolved in the | |
| context of the main repo, see [question | |
| above](#which-is-evaluated-first-module-bazel-or-workspace)), or use a target | |
| pattern (like `bazel fetch @foo//:bar`) to fetch all transitive dependencies of | |
| `@foo//:bar` (this is equivalent to `bazel build --nobuild @foo//:bar`). | |
| The make sure no fetches happen during a build, use `--nofetch`. More precisely, | |
| this makes any attempt to run a non-local repository rule fail. | |
| If you want to fetch repos _and_ modify them to test locally, consider using | |
| the [`bazel vendor`](vendor) command. | |
| ### How do I use HTTP proxies? {#how-do-i-use-http-proxies} | |
| Bazel respects the `http_proxy` and `HTTPS_PROXY` environment variables commonly | |
| accepted by other programs, such as | |
| [curl](https://everything.curl.dev/usingcurl/proxies/env.html). | |
| ### How do I make Bazel prefer IPv6 in dual-stack IPv4/IPv6 setups? {#ipv6} | |
| On IPv6-only machines, Bazel can download dependencies with no changes. However, | |
| on dual-stack IPv4/IPv6 machines Bazel follows the same convention as Java, | |
| preferring IPv4 if enabled. In some situations, for example when the IPv4 | |
| network cannot resolve/reach external addresses, this can cause `Network | |
| unreachable` exceptions and build failures. In these cases, you can override | |
| Bazel's behavior to prefer IPv6 by using the | |
| [`java.net.preferIPv6Addresses=true` system | |
| property](https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html). | |
| Specifically: | |
| * Use `--host_jvm_args=-Djava.net.preferIPv6Addresses=true` [startup | |
| option](/versions/9.3.0/docs/user-manual#startup-options), for example by adding the | |
| following line in your [`.bazelrc` file](/versions/9.3.0/run/bazelrc): | |
| `startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true` | |
| * When running Java build targets that need to connect to the internet (such | |
| as for integration tests), use the | |
| `--jvmopt=-Djava.net.preferIPv6Addresses=true` [tool | |
| flag](/versions/9.3.0/docs/user-manual#jvmopt). For example, include in your [`.bazelrc` | |
| file](/versions/9.3.0/run/bazelrc): | |
| `build --jvmopt=-Djava.net.preferIPv6Addresses` | |
| * If you are using | |
| [`rules_jvm_external`](https://github.com/bazelbuild/rules_jvm_external) for | |
| dependency version resolution, also add | |
| `-Djava.net.preferIPv6Addresses=true` to the `COURSIER_OPTS` environment | |
| variable to [provide JVM options for | |
| Coursier](https://github.com/bazelbuild/rules_jvm_external#provide-jvm-options-for-coursier-with-coursier_opts). | |
| ### Can repo rules be run remotely with remote execution? {#can-repo-rules-be-run-remotely-with-remote-execution} | |
| No; or at least, not yet. Users employing remote execution services to speed up | |
| their builds may notice that repo rules are still run locally. For example, an | |
| `http_archive` would be first downloaded onto the local machine (using any local | |
| download cache if applicable), extracted, and then each source file would be | |
| uploaded to the remote execution service as an input file. It's natural to ask | |
| why the remote execution service doesn't just download and extract that archive, | |
| saving a useless roundtrip. | |
| Part of the reason is that repo rules (and module extensions) are akin to | |
| "scripts" that are run by Bazel itself. A remote executor doesn't necessarily | |
| even have a Bazel installed. | |
| Another reason is that Bazel often needs the BUILD files in the downloaded and | |
| extracted archives to perform loading and analysis, which _are_ performed | |
| locally. | |
| There are preliminary ideas to solve this problem by re-imagining repo rules as | |
| build rules, which would naturally allow them to be run remotely, but conversely | |
| raise new architectural concerns (for example, the `query` commands would | |
| potentially need to run actions, complicating their design). | |
| For more previous discussion on this topic, see [A way to support repositories | |
| that need Bazel for being | |
| fetched](https://github.com/bazelbuild/bazel/discussions/20464). | |
| [npm-semver]: https://docs.npmjs.com/about-semantic-versioning | |
| [cargo-semver]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#version-requirement-syntax | |
| [go_deps]: https://github.com/bazel-contrib/rules_go/blob/master/docs/go/core/bzlmod.md#specifying-external-dependencies | |