| --- | |
| title: 'External dependencies overview' | |
| --- | |
| Bazel supports *external dependencies*, source files (both text and binary) used | |
| in your build that are not from your workspace. For example, they could be a | |
| ruleset hosted in a GitHub repo, a Maven artifact, or a directory on your local | |
| machine outside your current workspace. | |
| This document gives an overview of the system before examining some of the | |
| concepts in more detail. | |
| ## Overview of the system {#overview} | |
| Bazel's external dependency system works on the basis of [*Bazel | |
| modules*](#module), each of which is a versioned Bazel project, and | |
| [*repositories*](#repository) (or repos), which are directory trees containing | |
| source files. | |
| Bazel starts from the root module -- that is, the project you're working on. | |
| Like all modules, it needs to have a `MODULE.bazel` file at its directory root, | |
| declaring its basic metadata and direct dependencies. The following is a basic | |
| example: | |
| ```python | |
| module(name = "my-module", version = "1.0") | |
| bazel_dep(name = "rules_cc", version = "0.1.1") | |
| bazel_dep(name = "platforms", version = "0.0.11") | |
| ``` | |
| From there, Bazel looks up all transitive dependency modules in a | |
| [*Bazel registry*](registry) — by default, the [Bazel Central | |
| Registry](https://bcr.bazel.build/). The registry provides the | |
| dependencies' `MODULE.bazel` files, which allows Bazel to discover the entire | |
| transitive dependency graph before performing version resolution. | |
| After version resolution, in which one version is selected for each module, | |
| Bazel consults the registry again to learn how to define a repo for each module | |
| -- that is, how the sources for each dependency module should be fetched. Most | |
| of the time, these are just archives downloaded from the internet and extracted. | |
| Modules can also specify customized pieces of data called *tags*, which are | |
| consumed by [*module extensions*](extension) after module resolution | |
| to define additional repos. These extensions can perform actions like file I/O | |
| and sending network requests. Among other things, they allow Bazel to interact | |
| with other package management systems while also respecting the dependency graph | |
| built out of Bazel modules. | |
| The three kinds of repos -- the main repo (which is the source tree you're | |
| working in), the repos representing transitive dependency modules, and the repos | |
| created by module extensions -- form the [*workspace*](#workspace) together. | |
| External repos (non-main repos) are fetched on demand, for example when they're | |
| referred to by labels (like `@repo//pkg:target`) in BUILD files. | |
| ## Benefits {#benefits} | |
| Bazel's external dependency system offers a wide range of benefits. | |
| ### Automatic Dependency Resolution {#automatic-dependency-resolution} | |
| - **Deterministic Version Resolution**: Bazel adopts the deterministic | |
| [MVS](module#version-selection) version resolution algorithm, | |
| minimizing conflicts and addressing diamond dependency issues. | |
| - **Simplified Dependency Management**: `MODULE.bazel` declares only direct | |
| dependencies, while transitive dependencies are automatically resolved, | |
| providing a clearer overview of the project's dependencies. | |
| - **[Strict Dependency visibility](module#repository_names_and_strict_deps)**: | |
| Only direct dependencies are visible, ensuring correctness and | |
| predictability. | |
| ### Ecosystem Integration {#ecosystem-integration} | |
| - **[Bazel Central Registry](https://registry.bazel.build/)**: A centralized | |
| repository for discovering and managing common dependencies as Bazel | |
| modules. | |
| - **Adoption of Non-Bazel Projects**: When a non-Bazel project (usually a C++ | |
| library) is adapted for Bazel and made available in BCR, it streamlines its | |
| integration for the whole community and eliminates duplicated effort and | |
| conflicts of custom BUILD files. | |
| - **Unified Integration with Language-Specific Package Managers**: Rulesets | |
| streamline integration with external package managers for non-Bazel | |
| dependencies, including: | |
| * [rules_jvm_external](https://github.com/bazel-contrib/rules_jvm_external/blob/master/docs/bzlmod.md) | |
| for Maven, | |
| * [rules_python](https://rules-python.readthedocs.io/en/latest/pypi-dependencies.html#using-bzlmod) | |
| for PyPi, | |
| * [bazel-gazelle](https://github.com/bazel-contrib/rules_go/blob/master/docs/go/core/bzlmod.md#external-dependencies) | |
| for Go Modules, | |
| * [rules_rust](https://bazelbuild.github.io/rules_rust/crate_universe_bzlmod.html) | |
| for Cargo. | |
| ### Advanced Features {#advanced-features} | |
| - **[Module Extensions](extension)**: The | |
| [`use_repo_rule`](/versions/9.3.0/rules/lib/globals/module#use_repo_rule) and module | |
| extension features allow flexible use of custom repository rules and | |
| resolution logic to introduce any non-Bazel dependencies. | |
| - **[`bazel mod` Command](mod-command)**: The sub-command offers | |
| powerful ways to inspect external dependencies. You know exactly how an | |
| external dependency is defined and where it comes from. | |
| - **[Vendor Mode](vendor)**: Pre-fetch the exact external dependencies you | |
| need to facilitate offline builds. | |
| - **[Lockfile](lockfile)**: The lockfile improves build reproducibility and | |
| accelerates dependency resolution. | |
| - **(Upcoming) [BCR Provenance | |
| Attestations](https://github.com/bazelbuild/bazel-central-registry/discussions/2721)**: | |
| Strengthen supply chain security by ensuring verified provenance of | |
| dependencies. | |
| ## Concepts {#concepts} | |
| This section gives more detail on concepts related to external dependencies. | |
| ### Module {#module} | |
| A Bazel project that can have multiple versions, each of which can have | |
| dependencies on other modules. | |
| In a local Bazel workspace, a module is represented by a repository. | |
| For more details, see [Bazel modules](module). | |
| ### Repository {#repository} | |
| A directory tree with a boundary marker file at its root, containing source | |
| files that can be used in a Bazel build. Often shortened to just **repo**. | |
| A repo boundary marker file can be `MODULE.bazel` (signaling that this repo | |
| represents a Bazel module), `REPO.bazel` (see [below](#repo.bazel)), or in | |
| legacy contexts, `WORKSPACE` or `WORKSPACE.bazel`. Any repo boundary marker file | |
| will signify the boundary of a repo; multiple such files can coexist in a | |
| directory. | |
| ### Main repository {#main-repository} | |
| The repository in which the current Bazel command is being run. | |
| The root of the main repository is also known as the | |
| <span id="#workspace-root">**workspace root**</span>. | |
| ### Workspace {#workspace} | |
| The environment shared by all Bazel commands run in the same main repository. It | |
| encompasses the main repo and the set of all defined external repos. | |
| Note that historically the concepts of "repository" and "workspace" have been | |
| conflated; the term "workspace" has often been used to refer to the main | |
| repository, and sometimes even used as a synonym of "repository". | |
| ### Canonical repository name {#canonical-repo-name} | |
| The name by which a repository is always addressable. Within the context of a | |
| workspace, each repository has a single canonical name. A target inside a repo | |
| whose canonical name is `canonical_name` can be addressed by the label | |
| `@@canonical_name//package:target` (note the double `@`). | |
| The main repository always has the empty string as the canonical name. | |
| ### Apparent repository name {#apparent-repo-name} | |
| The name by which a repository is addressable in the context of a certain other | |
| repo. This can be thought of as a repo's "nickname": The repo with the canonical | |
| name `michael` might have the apparent name `mike` in the context of the repo | |
| `alice`, but might have the apparent name `mickey` in the context of the repo | |
| `bob`. In this case, a target inside `michael` can be addressed by the label | |
| `@mike//package:target` in the context of `alice` (note the single `@`). | |
| Conversely, this can be understood as a **repository mapping**: each repo | |
| maintains a mapping from "apparent repo name" to a "canonical repo name". | |
| ### Repository rule {#repo-rule} | |
| A schema for repository definitions that tells Bazel how to materialize a | |
| repository. For example, it could be "download a zip archive from a certain URL | |
| and extract it", or "fetch a certain Maven artifact and make it available as a | |
| `java_import` target", or simply "symlink a local directory". Every repo is | |
| **defined** by calling a repo rule with an appropriate number of arguments. | |
| See [Repository rules](repo) for more information about how to write | |
| your own repository rules. | |
| The most common repo rules by far are | |
| [`http_archive`](/versions/9.3.0/rules/lib/repo/http#http_archive), which downloads an archive | |
| from a URL and extracts it, and | |
| [`local_repository`](/versions/9.3.0/reference/be/workspace#local_repository), which symlinks a | |
| local directory that is already a Bazel repository. | |
| ### Fetch a repository {#fetch-repository} | |
| The action of making a repo available on local disk by running its associated | |
| repo rule. The repos defined in a workspace are not available on local disk | |
| before they are fetched. | |
| Normally, Bazel only fetches a repo when it needs something from the repo, | |
| and the repo hasn't already been fetched. If the repo has already been fetched | |
| before, Bazel only re-fetches it if its definition has changed. | |
| The `fetch` command can be used to initiate a pre-fetch for a repository, | |
| target, or all necessary repositories to perform any build. This capability | |
| enables offline builds using the `--nofetch` option. | |
| The `--fetch` option serves to manage network access. Its default value is true. | |
| However, when set to false (`--nofetch`), the command will utilize any cached | |
| version of the dependency, and if none exists, the command will result in | |
| failure. | |
| See [fetch options](/versions/9.3.0/reference/command-line-reference#fetch-options) for more | |
| information about controlling fetch. | |
| ### Directory layout {#directory-layout} | |
| After being fetched, the repo can be found in the subdirectory `external` in the | |
| [output base](/versions/9.3.0/remote/output-directories), under its canonical name. | |
| You can run the following command to see the contents of the repo with the | |
| canonical name `canonical_name`: | |
| ```posix-terminal | |
| ls $(bazel info output_base)/external/<var> canonical_name </var> | |
| ``` | |
| ### REPO.bazel file {#repo.bazel} | |
| The [`REPO.bazel`](/versions/9.3.0/rules/lib/globals/repo) file is used to mark the topmost | |
| boundary of the directory tree that constitutes a repo. It doesn't need to | |
| contain anything to serve as a repo boundary file; however, it can also be used | |
| to specify some common attributes for all build targets inside the repo. | |
| The syntax of a `REPO.bazel` file is similar to `BUILD` files, except that no | |
| `load` statements are supported. The `repo()` function takes the same arguments as the [`package()` | |
| function](/versions/9.3.0/reference/be/functions#package) in `BUILD` files; whereas `package()` | |
| specifies common attributes for all build targets inside the package, `repo()` | |
| analogously does so for all build targets inside the repo. | |
| For example, you can specify a common license for all targets in your repo by | |
| having the following `REPO.bazel` file: | |
| ```python | |
| repo( | |
| default_package_metadata = ["//:my_license"], | |
| ) | |
| ``` | |
| ## The legacy WORKSPACE system {#workspace-system} | |
| In older Bazel versions (before 9.0), external dependencies were introduced by | |
| defining repos in the `WORKSPACE` (or `WORKSPACE.bazel`) file. This file has a | |
| similar syntax to `BUILD` files, employing repo rules instead of build rules. | |
| The following snippet is an example to use the `http_archive` repo rule in the | |
| `WORKSPACE` file: | |
| ```python | |
| load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") | |
| http_archive( | |
| name = "foo", | |
| urls = ["https://example.com/foo.zip"], | |
| sha256 = "c9526390a7cd420fdcec2988b4f3626fe9c5b51e2959f685e8f4d170d1a9bd96", | |
| ) | |
| ``` | |
| The snippet defines a repo whose canonical name is `foo`. In the `WORKSPACE` | |
| system, by default, the canonical name of a repo is also its apparent name to | |
| all other repos. | |
| See the [full list](/versions/9.3.0/rules/lib/globals/workspace) of functions available in | |
| `WORKSPACE` files. | |
| ### Shortcomings of the `WORKSPACE` system {#workspace-shortcomings} | |
| In the years after the `WORKSPACE` system was introduced, users reported many | |
| pain points, including: | |
| * Bazel does not evaluate the `WORKSPACE` files of any dependencies, so all | |
| transitive dependencies must be defined in the `WORKSPACE` file of the main | |
| repo, in addition to direct dependencies. | |
| * To work around this, projects have adopted the "deps.bzl" pattern, in which | |
| they define a macro which in turn defines multiple repos, and ask users to | |
| call this macro in their `WORKSPACE` files. | |
| * This has its own problems: macros cannot `load` other `.bzl` files, so | |
| these projects have to define their transitive dependencies in this | |
| "deps" macro, or work around this issue by having the user call multiple | |
| layered "deps" macros. | |
| * Bazel evaluates the `WORKSPACE` file sequentially. Additionally, | |
| dependencies are specified using `http_archive` with URLs, without any | |
| version information. This means that there is no reliable way to perform | |
| version resolution in the case of diamond dependencies (`A` depends on | |
| `B` and `C`; `B` and `C` both depend on different versions of `D`). | |
| Due to the shortcomings of WORKSPACE, the new module-based system (codenamed | |
| "Bzlmod") gradually replaced the legacy WORKSPACE system between Bazel 6 and 9. | |
| Read the [Bzlmod migration guide](migration) on how to migrate | |
| to Bzlmod. | |
| ### External links on Bzlmod {#external-links} | |
| * [Bzlmod usage examples in bazelbuild/examples](https://github.com/bazelbuild/examples/tree/main/bzlmod) | |
| * [Bazel External Dependencies Overhaul](https://docs.google.com/document/d/1moQfNcEIttsk6vYanNKIy3ZuK53hQUFq1b1r0rmsYVg/edit) | |
| (original Bzlmod design doc) | |
| * [BazelCon 2021 talk on Bzlmod](https://www.youtube.com/watch?v=TxOCKtU39Fs) | |
| * [Bazel Community Day talk on Bzlmod](https://www.youtube.com/watch?v=MB6xxis9gWI) |