Vendor Mode

Report an issue View source Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Vendor mode is a feature of Bzlmod that lets you create a local copy of external dependencies. This is useful for offline builds, or when you want to control the source of an external dependency.

Enable vendor mode

You can enable vendor mode by specifying --vendor_dir flag.

For example, by adding it to your .bazelrc file:

# Enable vendor mode with vendor directory under <workspace>/vendor_src
common --vendor_dir=vendor_src

The vendor directory can be either a relative path to your workspace root or an absolute path.

Vendor a specific external repository

You can use the vendor command with the --repo flag to specify which repo to vendor, it accepts both canonical repo name and apparent repo name.

For example, running:

bazel vendor --vendor_dir=vendor_src --repo=@rules_cc

or

bazel vendor --vendor_dir=vendor_src --repo=@@rules_cc~

will both get rules_cc to be vendored under <workspace root>/vendor_src/rules_cc~.

Vendor external dependencies for given targets

To vendor all external dependencies required for building given target patterns, you can run bazel vendor <target patterns>.

For example

bazel vendor --vendor_dir=vendor_src //src/main:hello-world //src/test/...

will vendor all repos required for building the //src/main:hello-world target and all targets under //src/test/... with the current configuration.

Under the hood, it's doing a bazel build --nobuild command to analyze the target patterns, therefore build flags could be applied to this command and affect the result.

Build the target offline

With the external dependencies vendored, you can build the target offline by

bazel build --vendor_dir=vendor_src //src/main:hello-world //src/test/...

The build should work in a clean build environment without network access and repository cache.

Therefore, you should be able to check in the vendored source and build the same targets offline on another machine.

Vendor all external dependencies

To vendor all repos in your transitive external dependencies graph, you can run:

bazel vendor --vendor_dir=vendor_src

Note that vendoring all dependencies has a few disadvantages:

  • Fetching all repos, including those introduced transitively, can be time-consuming.
  • The vendor directory can become very large.
  • Some repos may fail to fetch if they are not compatible with the current platform or environment.

Therefore, consider vendoring for specific targets first.

Configure vendor mode with VENDOR.bazel

You can control how given repos are handled with the VENDOR.bazel file located under the vendor directory.

There are two directives available, both accepting a list of canonical repo names as arguments:

  • ignore(): to completely ignore a repository from vendor mode.
  • pin(): to pin a repository to its current vendored source as if there is a --override_repository flag for this repo. Bazel will NOT update the vendored source for this repo while running the vendor command unless it's unpinned. The user can modify and maintain the vendored source for this repo manually.

For example

ignore("@@rules_cc~")
pin("@@bazel_skylib~")

With this configuration

  • Both repos will be excluded from subsequent vendor commands.
  • Repo bazel_skylib will be overridden to the source located under the vendor directory.
  • The user can safely modify the vendored source of bazel_skylib.
  • To re-vendor bazel_skylib, the user has to disable the pin statement first.

Understand how vendor mode works

Bazel fetches external dependencies of a project under $(bazel info output_base)/external. Vendoring external dependencies means moving out relevant files and directories to the given vendor directory and use the vendored source for later builds.

The content being vendored includes:

  • The repo directory
  • The repo marker file

During a build, if the vendored marker file is up-to-date or the repo is pinned in the VENDOR.bazel file, then Bazel uses the vendored source by creating a symlink to it under $(bazel info output_base)/external instead of actually running the repository rule. Otherwise, a warning is printed and Bazel will fallback to fetching the latest version of the repo.

Vendor registry files

Bazel has to perform the Bazel module resolution in order to fetch external dependencies, which may require accessing registry files through internet. To achieve offline build, Bazel vendors all registry files fetched from network under the <vendor_dir>/_registries directory.

External repositories may contain symlinks pointing to other files or directories. To make sure symlinks work correctly, Bazel uses the following strategy to rewrite symlinks in the vendored source:

  • Create a symlink <vendor_dir>/bazel-external that points to $(bazel info output_base)/external. It is refreshed by every Bazel command automatically.
  • For the vendored source, rewrite all symlinks that originally point to a path under $(bazel info output_base)/external to a relative path under <vendor_dir>/bazel-external.

For example, if the original symlink is

<vendor_dir>/repo_foo~/link  =>  $(bazel info output_base)/external/repo_bar~/file

It will be rewritten to

<vendor_dir>/repo_foo~/link  =>  ../../bazel-external/repo_bar~/file

where

<vendor_dir>/bazel-external  =>  $(bazel info output_base)/external  # This might be new if output base is changed

Since <vendor_dir>/bazel-external is generated by Bazel automatically, it's recommended to add it to .gitignore or equivalent to avoid checking it in.

With this strategy, symlinks in the vendored source should work correctly even after the vendored source is moved to another location or the bazel output base is changed.