| --- | |
| 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. | |
| As of Bazel 6.0, there are two ways to manage external dependencies with Bazel: | |
| the traditional, repository-focused [`WORKSPACE` system](#workspace-system), and | |
| the newer module-focused [`MODULE.bazel` system](#bzlmod) (codenamed *Bzlmod*, | |
| and enabled with the flag `--enable_bzlmod`). The two systems can be used | |
| together, but Bzlmod is replacing the `WORKSPACE` system in future Bazel | |
| releases, check the [Bzlmod migration guide](/versions/8.8.1/external/migration) on how to | |
| migrate. | |
| This document explains the concepts surrounding external dependency management | |
| in Bazel, before going into a bit more detail about the two systems in order. | |
| ## Concepts | |
| ### 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 | |
| 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 | |
| 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 | |
| The canonical name a repository is addressable by. 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 | |
| The name a repository is addressable by 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 | |
| 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](/versions/8.8.1/extending/repo) for more information about how to write | |
| your own repository rules. | |
| The most common repo rules by far are | |
| [`http_archive`](/versions/8.8.1/rules/lib/repo/http#http_archive), which downloads an archive | |
| from a URL and extracts it, and | |
| [`local_repository`](/versions/8.8.1/reference/be/workspace#local_repository), which symlinks a | |
| local directory that is already a Bazel repository. | |
| ### Fetch a 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/8.8.1/reference/command-line-reference#fetch-options) for more | |
| information about controlling fetch. | |
| ### Directory layout | |
| After being fetched, the repo can be found in the subdirectory `external` in the | |
| [output base](/versions/8.8.1/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 | |
| The `REPO.bazel` 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, and only a single function, `repo()`, is | |
| available. `repo()` takes the same arguments as the [`package()` | |
| function](/versions/8.8.1/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"], | |
| ) | |
| ``` | |
| ## Manage external dependencies with Bzlmod | |
| Bzlmod, the new external dependency subsystem, does not directly work with repo | |
| definitions. Instead, it builds a dependency graph from _modules_, runs | |
| _extensions_ on top of the graph, and defines repos accordingly. | |
| A [Bazel **module**](/versions/8.8.1/external/module) is a Bazel project that can have multiple | |
| versions, each of which publishes metadata about other modules that it depends | |
| on. A module must have a `MODULE.bazel` file at its repo root, next to the | |
| `WORKSPACE` file. This file is the module's manifest, declaring its name, | |
| version, list of dependencies, among other information. The following is 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") | |
| ``` | |
| A module must only list its direct dependencies, which Bzlmod looks up in a | |
| [Bazel registry](/versions/8.8.1/external/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 | |
| (in most cases, using `http_archive`). | |
| Modules can also specify customized pieces of data called *tags*, which are | |
| consumed by [**module extensions**](/versions/8.8.1/external/extension) after module resolution | |
| to define additional repos. These extensions have capabilities similar to repo | |
| rules, enabling them to 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. | |
| ### External links on Bzlmod | |
| * [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) | |
| ## Define repos with `WORKSPACE` | |
| Historically, you can manage external dependencies 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/8.8.1/rules/lib/globals/workspace) of functions available in | |
| `WORKSPACE` files. | |
| ### Shortcomings of the `WORKSPACE` system | |
| In the years since the `WORKSPACE` system was introduced, users have 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, Bzlmod is going to replace the legacy | |
| WORKSPACE system in future Bazel releases. Please read the [Bzlmod migration | |
| guide](/versions/8.8.1/external/migration) on how to migrate to Bzlmod. |