| Project: /_project.yaml |
| Book: /_book.yaml |
| |
| # Bazel modules |
| |
| {% include "_buttons.html" %} |
| |
| A Bazel **module** is a Bazel project that can have multiple versions, each of |
| which publishes metadata about other modules that it depends on. This is |
| analogous to familiar concepts in other dependency management systems, such as a |
| Maven *artifact*, an npm *package*, a Go *module*, or a Cargo *crate*. |
| |
| A module must have a `MODULE.bazel` file at its repo root. This file is the |
| module's manifest, declaring its name, version, list of direct dependencies, and |
| other information. For a basic example: |
| |
| ```python |
| module(name = "my-module", version = "1.0") |
| |
| bazel_dep(name = "rules_cc", version = "0.0.1") |
| bazel_dep(name = "protobuf", version = "3.19.0") |
| ``` |
| |
| See the [full list](/rules/lib/globals/module) of directives available in |
| `MODULE.bazel` files. |
| |
| To perform module resolution, Bazel starts by reading the root module's |
| `MODULE.bazel` file, and then repeatedly requests any dependency's |
| `MODULE.bazel` file from a [Bazel registry](/external/registry) until it |
| discovers the entire dependency graph. |
| |
| By default, Bazel then [selects](#version-selection) one version of each module |
| to use. Bazel represents each module with a repo, and consults the registry |
| again to learn how to define each of the repos. |
| |
| ## Version format |
| |
| Bazel has a diverse ecosystem and projects use various versioning schemes. The |
| most popular by far is [SemVer](https://semver.org){: .external}, but there are |
| also prominent projects using different schemes such as |
| [Abseil](https://github.com/abseil/abseil-cpp/releases){: .external}, whose |
| versions are date-based, for example `20210324.2`). |
| |
| For this reason, Bzlmod adopts a more relaxed version of the SemVer spec. The |
| differences include: |
| |
| * SemVer prescribes that the "release" part of the version must consist of 3 |
| segments: `MAJOR.MINOR.PATCH`. In Bazel, this requirement is loosened so |
| that any number of segments is allowed. |
| * In SemVer, each of the segments in the "release" part must be digits only. |
| In Bazel, this is loosened to allow letters too, and the comparison |
| semantics match the "identifiers" in the "prerelease" part. |
| * Additionally, the semantics of major, minor, and patch version increases are |
| not enforced. However, see [compatibility level](#compatibility_level) for |
| details on how we denote backwards compatibility. |
| |
| Any valid SemVer version is a valid Bazel module version. Additionally, two |
| SemVer versions `a` and `b` compare `a < b` if and only if the same holds when |
| they're compared as Bazel module versions. |
| |
| ## Version selection {:#version-selection} |
| |
| Consider the diamond dependency problem, a staple in the versioned dependency |
| management space. Suppose you have the dependency graph: |
| |
| ``` |
| A 1.0 |
| / \ |
| B 1.0 C 1.1 |
| | | |
| D 1.0 D 1.1 |
| ``` |
| |
| Which version of `D` should be used? To resolve this question, Bzlmod uses the |
| [Minimal Version Selection](https://research.swtch.com/vgo-mvs){: .external} |
| (MVS) algorithm introduced in the Go module system. MVS assumes that all new |
| versions of a module are backwards compatible, and so picks the highest version |
| specified by any dependent (`D 1.1` in our example). It's called "minimal" |
| because `D 1.1` is the earliest version that could satisfy our requirements — |
| even if `D 1.2` or newer exists, we don't select them. Using MVS creates a |
| version selection process that is *high-fidelity* and *reproducible*. |
| |
| ### Yanked versions |
| |
| The registry can declare certain versions as *yanked* if they should be avoided |
| (such as for security vulnerabilities). Bazel throws an error when selecting a |
| yanked version of a module. To fix this error, either upgrade to a newer, |
| non-yanked version, or use the |
| [`--allow_yanked_versions`](/reference/command-line-reference#flag--allow_yanked_versions) |
| flag to explicitly allow the yanked version. |
| |
| ## Compatibility level |
| |
| In Go, MVS's assumption about backwards compatibility works because it treats |
| backwards incompatible versions of a module as a separate module. In terms of |
| SemVer, that means `A 1.x` and `A 2.x` are considered distinct modules, and can |
| coexist in the resolved dependency graph. This is, in turn, made possible by |
| encoding the major version in the package path in Go, so there aren't any |
| compile-time or linking-time conflicts. |
| |
| Bazel, however, cannot provide such guarantees, so it needs the "major version" |
| number in order to detect backwards incompatible versions. This number is called |
| the *compatibility level*, and is specified by each module version in its |
| `module()` directive. With this information, Bazel can throw an error when it |
| detects that versions of the same module with different compatibility levels |
| exist in the resolved dependency graph. |
| |
| ## Overrides |
| |
| Specify overrides in the `MODULE.bazel` file to alter the behavior of Bazel |
| module resolution. Only the root module's overrides take effect — if a module is |
| used as a dependency, its overrides are ignored. |
| |
| Each override is specified for a certain module name, affecting all of its |
| versions in the dependency graph. Although only the root module's overrides take |
| effect, they can be for transitive dependencies that the root module does not |
| directly depend on. |
| |
| ### Single-version override |
| |
| The [`single_version_override`](/rules/lib/globals/module#single_version_override) |
| serves multiple purposes: |
| |
| * With the `version` attribute, you can pin a dependency to a specific |
| version, regardless of which versions of the dependency are requested in the |
| dependency graph. |
| * With the `registry` attribute, you can force this dependency to come from a |
| specific registry, instead of following the normal [registry |
| selection](/external/registry#selecting_registries) process. |
| * With the `patch*` attributes, you can specify a set of patches to apply to |
| the downloaded module. |
| |
| These attributes are all optional and can be mixed and matched with each other. |
| |
| ### Multiple-version override |
| |
| A [`multiple_version_override`](/rules/lib/globals/module#multiple_version_override) |
| can be specified to allow multiple versions of the same module to coexist in the |
| resolved dependency graph. |
| |
| You can specify an explicit list of allowed versions for the module, which must |
| all be present in the dependency graph before resolution — there must exist |
| *some* transitive dependency depending on each allowed version. After |
| resolution, only the allowed versions of the module remain, while Bazel upgrades |
| other versions of the module to the nearest higher allowed version at the same |
| compatibility level. If no higher allowed version at the same compatibility |
| level exists, Bazel throws an error. |
| |
| For example, if versions `1.1`, `1.3`, `1.5`, `1.7`, and `2.0` exist in the |
| dependency graph before resolution and the major version is the compatibility |
| level: |
| |
| * A multiple-version override allowing `1.3`, `1.7`, and `2.0` results in |
| `1.1` being upgraded to `1.3`, `1.5` being upgraded to `1.7`, and other |
| versions remaining the same. |
| * A multiple-version override allowing `1.5` and `2.0` results in an error, as |
| `1.7` has no higher version at the same compatibility level to upgrade to. |
| * A multiple-version override allowing `1.9` and `2.0` results in an error, as |
| `1.9` is not present in the dependency graph before resolution. |
| |
| Additionally, users can also override the registry using the `registry` |
| attribute, similarly to single-version overrides. |
| |
| ### Non-registry overrides |
| |
| Non-registry overrides completely remove a module from version resolution. Bazel |
| does not request these `MODULE.bazel` files from a registry, but instead from |
| the repo itself. |
| |
| Bazel supports the following non-registry overrides: |
| |
| * [`archive_override`](/rules/lib/globals/module#archive_override) |
| * [`git_override`](/rules/lib/globals/module#git_override) |
| * [`local_path_override`](/rules/lib/globals/module#local_path_override) |
| |
| ## Define repos that don't represent Bazel modules {:#use_repo_rule} |
| |
| With `bazel_dep`, you can define repos that represent other Bazel modules. |
| Sometimes there is a need to define a repo that does _not_ represent a Bazel |
| module; for example, one that contains a plain JSON file to be read as data. |
| |
| In this case, you could use the [`use_repo_rule` |
| directive](/rules/lib/globals/module#use_repo_rule) to directly define a repo |
| by invoking a repo rule. This repo will only be visible to the module it's |
| defined in. |
| |
| Under the hood, this is implemented using the same mechanism as [module |
| extensions](/external/extension), which lets you define repos with more |
| flexibility. |
| |
| ## Repository names and strict deps |
| |
| The [apparent name](/external/overview#apparent-repo-name) of a repo backing a |
| module to its direct dependents defaults to its module name, unless the |
| `repo_name` attribute of the [`bazel_dep`](/rules/lib/globals/module#bazel_dep) |
| directive says otherwise. Note that this means a module can only find its direct |
| dependencies. This helps prevent accidental breakages due to changes in |
| transitive dependencies. |
| |
| The [canonical name](/external/overview#canonical-repo-name) of a repo backing a |
| module is either `{{ "<var>" }}module_name{{ "</var>" }}+{{ "<var>" }}version{{ |
| "</var>" }}` (for example, `bazel_skylib+1.0.3`) or `{{ "<var>" }}module_name{{ |
| "</var>" }}+` (for example, `bazel_features+`), depending on whether there are |
| multiple versions of the module in the entire dependency graph (see |
| [`multiple_version_override`](/rules/lib/globals/module#multiple_version_override)). |
| Note that **the canonical name format** is not an API you should depend on and |
| **is subject to change at any time**. Instead of hard-coding the canonical name, |
| use a supported way to get it directly from Bazel: |
| * In BUILD and `.bzl` files, use |
| [`Label.repo_name`](/rules/lib/builtins/Label#repo_name) on a `Label` instance |
| constructed from a label string given by the apparent name of the repo, e.g., |
| `Label("@bazel_skylib").repo_name`. |
| * When looking up runfiles, use |
| [`$(rlocationpath ...)`](https://bazel.build/reference/be/make-variables#predefined_label_variables) |
| or one of the runfiles libraries in |
| `@bazel_tools//tools/{bash,cpp,java}/runfiles` or, for a ruleset `rules_foo`, |
| in `@rules_foo//foo/runfiles`. |
| * When interacting with Bazel from an external tool such as an IDE or language |
| server, use the `bazel mod dump_repo_mapping` command to get the mapping from |
| apparent names to canonical names for a given set of repositories. |
| |
| [Module extensions](/external/extension) can also introduce additional repos |
| into the visible scope of a module. |