site/en/external/migration_tool.md
Project: /_project.yaml Book: /_book.yaml keywords: bzlmod
{# disableFinding(LINE_OVER_80_LINK) #} {# disableFinding(SNIPPET_NO_LANG) #} {# disableFinding(LINK_MISSING_ID) #} {# disableFinding("repo") #}
{% include "_buttons.html" %}
To simplify the often complex process of moving from WORKSPACE to Bzlmod, it's
highly recommended to use the migration script. This helper
tool automates many of the steps involved in migrating your external dependency
management system.
Note: If you want to try out the AI driven Bzlmod migration, check Bzlmod Migration Agent Setup.
The script's primary functions are:
WORKSPACE
file to identify external repositories used by specified build targets,
using Bazel's
experimental_repository_resolved_file
flag to generate a resolved dependencies file containing this information.bazel query to determine which
repositories are direct dependencies for the specified targets.WORKSPACE dependencies into
their Bzlmod equivalents. This is a two-step process:
MODULE.bazel file.migration_info.md file that
documents the migration process. This report includes a list of direct
dependencies, the generated Bzlmod declarations, and any manual steps that
may be required to complete the migration.The migration tool supports:
Important Notes:
Before you begin:
Upgrade to the latest Bazel 7 release, which provides robust support for both WORKSPACE and Bzlmod.
Verify the following command runs successfully for your project's main build targets:
bazel build --nobuild --enable_workspace --noenable_bzlmod <targets>
Once the prerequisites are met, run the following commands to use the migration tool:
<pre class="prettyprint lang-shell" style="font-size: 12px;"> # Clone the Bazel Central Registry repository git clone https://github.com/bazelbuild/bazel-central-registry.git cd bazel-central-registry # Build the migration tool bazel build //tools:migrate_to_bzlmod # Create a convenient alias for the tool alias migrate2bzlmod=$(realpath ./bazel-bin/tools/migrate_to_bzlmod) # Navigate to your project's root directory and run the tool cd <your project root> migrate2bzlmod -t <targets> </pre>MODULE.bazel - The central manifest file for Bzlmod, which declares the
project's metadata and its direct dependencies on other Bazel modules.migration_info.md - A file providing step-by-step instructions on how the
migration tool was executed, designed to assist in the manual completion of
the migration process, if necessary.resolved_deps.py - Contains a comprehensive list of the project's external
dependencies, generated by analyzing the project's WORKSPACE file, serving
as a reference during the transition.query_direct_deps - Contains migration-relevant information regarding the
utilized targets, obtained by invoking Bazel with --output=build on the
project's WORKSPACE file. This file is primarily consumed by the migration
script.extension_for_XXX - A file containing a module extension
definition. The migration tool generates these files for dependencies that
are not standard Bazel modules but can be managed using Bzlmod's module
extensions.Flags available in this migration scripts are:
--t/--target: Targets to migrate. This flag is repeatable, and the
targets are accumulated.--i/--initial: Deletes MODULE.bazel, resolved_deps.py,
migration_info.md files and starts from scratch - Detect direct
dependencies, introduce them in MODULE.bazel and rerun generation of
resolved dependencies.migration_info.md, resolved_deps.py and query_direct_deps.MODULE.bazel file which were used for the
migration, such as # -- bazel_dep definitions -- #.To see the migration script in action, consider the following scenario when
Python, Maven and Go dependencies are declared in WORKSPACE file.
workspace(name="example")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load(":my_custom_macro.bzl", "my_custom_macro")
http_archive(
name = "rules_cc",
sha256 = "b8b918a85f9144c01f6cfe0f45e4f2838c7413961a8ff23bc0c6cdf8bb07a3b6",
strip_prefix = "rules_cc-0.1.5",
urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.1.5/rules_cc-0.1.5.tar.gz"],
)
# Module dependency
# -------------------
http_archive(
name = "rules_shell",
sha256 = "3e114424a5c7e4fd43e0133cc6ecdfe54e45ae8affa14fadd839f29901424043",
strip_prefix = "rules_shell-0.4.0",
url = "https://github.com/bazelbuild/rules_shell/releases/download/v0.4.0/rules_shell-v0.4.0.tar.gz",
)
# Repo rule
# -------------------
http_archive(
name = "com_github_cockroachdb_cockroach",
sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502",
strip_prefix = "cockroach-22.1.6",
url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz",
)
# Module extension
# -------------------
# Macro which invokes repository_rule
my_custom_macro(
name = "my_custom_repo",
)
# Go dependencies
# -------------------
http_archive(
name = "io_bazel_rules_go",
integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
],
)
http_archive(
name = "bazel_gazelle",
integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
],
)
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
go_rules_dependencies()
go_register_toolchains(version = "1.23.1")
gazelle_dependencies()
go_repository(
name = "org_golang_x_net",
importpath = "golang.org/x/net",
sum = "h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=",
version = "v0.0.0-20190311183353-d8887717615a",
build_file_proto_mode = "disable",
build_naming_convention = "import",
)
# Python dependencies
# -------------------
http_archive(
name = "rules_python",
integrity = "sha256-qDdnnxOC8mlowe5vg5x9r5B5qlMSgGmh8oFd7KpjcwQ=",
strip_prefix = "rules_python-1.4.0",
url = "https://github.com/bazelbuild/rules_python/releases/download/1.4.0/rules_python-1.4.0.tar.gz",
)
load("@rules_python//python:repositories.bzl", "py_repositories")
py_repositories()
load("@rules_python//python:pip.bzl", "pip_parse")
pip_parse(
name = "my_python_deps",
requirements_lock = "@example//:requirements_lock.txt",
)
load("@my_python_deps//:requirements.bzl", "install_deps")
install_deps()
load("@rules_python//python:repositories.bzl", "python_register_toolchains")
python_register_toolchains(
name = "python_3_11",
python_version = "3.11",
)
# Maven dependencies
# __________________
RULES_JVM_EXTERNAL_TAG = "4.5"
RULES_JVM_EXTERNAL_SHA = "b17d7388feb9bfa7f2fa09031b32707df529f26c91ab9e5d909eb1676badd9a6"
http_archive(
name = "rules_jvm_external",
strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
sha256 = RULES_JVM_EXTERNAL_SHA,
url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)
load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
rules_jvm_external_deps()
load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
rules_jvm_external_setup()
load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
name = "px_deps",
artifacts = [
"org.antlr:antlr4:4.11.1",
],
repositories = [
"https://repo1.maven.org/maven2",
],
)
Moreover, to demonstrate usage of module extension, custom macro is invoked from
WORKSPACE and it is defined in my_custom_macro.bzl.
"""Repo rule and macro used for testing"""
def _test_repo_rule_impl(repository_ctx):
repository_ctx.file(
"BUILD",
content = """
genrule(
name = "foo",
outs = ["rule_name.out"],
cmd = "touch $@",
visibility = ["//visibility:public"],
)
"""
)
_test_repo_rule = repository_rule(
implementation = _test_repo_rule_impl,
)
def my_custom_macro(name):
_test_repo_rule(name = name)
The end goal is to have MODULE.bazel file and delete the WORKSPACE file,
without impacting the user experience.
The first step is to follow How to Use the Migration Tool, which mostly is checking the bazel version (it must be Bazel 7) and adding an alias to the migration script.
Then, running migrate2bzlmod -t=//... outputs:
which gives the following important information:
./resolved_deps.py file, which contains info about all external
repositories declared and loaded using your WORKSPACE file.RESOLVED keyword describes all dependencies which are resolved by the tool
and added to the MODULE.bazel file.IMPORTANT keyword describes significant information worth investing time.--nobuild flag.migration_info.md file contains details about the migration. Check details
at this section.This section illustrates the migration of code from the WORKSPACE file to
MODULE.bazel.
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
go_rules_dependencies() go_register_toolchains(version = "1.23.1") gazelle_dependencies()
go_repository( name = "org_golang_x_net", importpath = "golang.org/x/net", sum = "h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=", version = "v0.0.0-20190311183353-d8887717615a", build_file_proto_mode = "disable", build_naming_convention = "import", ) </pre>
</div> <div style="flex: 1; min-width: 300px;"> <p><strong>MODULE.bazel - Go Extension</strong></p> <pre class="prettyprint lang-py" style="font-size: 12px;"> go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps") go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk")go_deps.from_file(go_mod = "//:go.mod") use_repo(go_deps, "org_golang_x_net") go_sdk.from_file(go_mod = "//:go.mod")
go_deps.gazelle_override( path = "golang.org/x/net", directives = [ "gazelle:proto disable", "gazelle:go_naming_convention import", ], ) </pre>
</div> </div> <hr style="height: 1px; background-color: black; border: none;"> <div style="display: flex; flex-wrap: wrap; gap: 16px;"> <div style="flex: 1; min-width: 300px;"> <p><strong>WORKSPACE - Python Extension</strong></p> <pre class="prettyprint lang-java" style="font-size: 12px;"> http_archive( name = "rules_python", integrity = "sha256-qDdnnxOC8mlowe5vg5x9r5B5qlMSgGmh8oFd7KpjcwQ=", strip_prefix = "rules_python-1.4.0", url = "https://github.com/bazelbuild/rules_python/releases/download/1.4.0/rules_python-1.4.0.tar.gz", )load("@rules_python//python:repositories.bzl", "py_repositories") py_repositories()
load("@rules_python//python:pip.bzl", "pip_parse") pip_parse( name = "my_python_deps", requirements_lock = "@example//:requirements_lock.txt", )
load("@my_python_deps//:requirements.bzl", "install_deps") install_deps()
load("@rules_python//python:repositories.bzl", "python_register_toolchains") python_register_toolchains( name = "python_3_11", python_version = "3.11", ) </pre>
</div> <div style="flex: 1; min-width: 300px;"> <p><strong>MODULE.bazel - Python Extension</strong></p> <pre class="prettyprint lang-py" style="font-size: 12px;"> pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") pip.parse( hub_name = "my_python_deps", python_version = "3.11", requirements_lock = "//:requirements_lock.txt", ) use_repo(pip, "my_python_deps")python = use_extension("@rules_python//python/extensions:python.bzl", "python") python.defaults(python_version = "3.11") python.toolchain(python_version = "3.11") </pre>
</div> </div> <hr style="height: 1px; background-color: black; border: none;"> <div style="display: flex; flex-wrap: wrap; gap: 16px;"> <div style="flex: 1; min-width: 300px;"> <p><strong>WORKSPACE - Maven Extension</strong></p> <pre class="prettyprint lang-java" style="font-size: 12px;">RULES_JVM_EXTERNAL_TAG = "4.5" RULES_JVM_EXTERNAL_SHA = "b17d7388feb9bfa7f2fa09031b32707df529f26c91ab9e5d909eb1676badd9a6"
http_archive( name = "rules_jvm_external", strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG, sha256 = RULES_JVM_EXTERNAL_SHA, url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG, )
load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps") rules_jvm_external_deps() load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup") rules_jvm_external_setup()
load("@rules_jvm_external//:defs.bzl", "maven_install") maven_install( name = "px_deps", artifacts = [ "org.antlr:antlr4:4.11.1", ], repositories = [ "https://repo1.maven.org/maven2", ], ) </pre>
</div> <div style="flex: 1; min-width: 300px;"> <p><strong>MODULE.bazel - Maven Extension</strong></p> <pre class="prettyprint lang-py" style="font-size: 12px;"> bazel_dep(name = "rules_jvm_external", version = "6.8")maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") use_repo(maven, "px_deps")
maven.artifact( name = "px_deps", group = "org.antlr", artifact = "antlr4", version = "4.11.1" ) </pre>
</div> </div> <hr style="height: 1px; background-color: black; border: none;"> <div style="display: flex; flex-wrap: wrap; gap: 16px;"> <div style="flex: 1; min-width: 300px;"> <p><strong>WORKSPACE - Repo rule</strong></p> <pre class="prettyprint lang-java" style="font-size: 12px;"> load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")http_archive( name = "com_github_cockroachdb_cockroach", sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502", strip_prefix = "cockroach-22.1.6", url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz", ) </pre>
</div> <div style="flex: 1; min-width: 300px;"> <p><strong>MODULE.bazel - Repo rule</strong></p> <pre class="prettyprint lang-py" style="font-size: 12px;"> http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")http_archive( name = "com_github_cockroachdb_cockroach", url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz", sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502", strip_prefix = "cockroach-22.1.6", ) </pre>
</div> </div> <hr style="height: 1px; background-color: black; border: none;"> <div style="display: flex; flex-wrap: wrap; gap: 16px;"> <div style="flex: 1; min-width: 300px;"> <p><strong>WORKSPACE - Module extension</strong></p> <pre class="prettyprint lang-java" style="font-size: 12px;"> load(":my_custom_macro.bzl", "my_custom_macro")my_custom_macro( name = "my_custom_repo", ) </pre>
</div> <div style="flex: 1; min-width: 300px;"> <p><strong>MODULE.bazel - Module extension</strong></p> <pre class="prettyprint lang-py" style="font-size: 12px;"> extension_for_my_custom_macro = use_extension("//:extension_for_my_custom_macro.bzl", "extension_for_my_custom_macro") use_repo(extension_for_my_custom_macro, "my_custom_repo") </pre> <p><strong>extension_for_my_custom_macro.bzl</strong></p> <pre class="prettyprint lang-py" style="font-size: 12px;"> load("//:my_custom_macro.bzl", "my_custom_macro")def _extension_for_my_custom_macro_impl(ctx): my_custom_macro( name = "my_custom_repo", )
extension_for_my_custom_macro = module_extension(implementation = _extension_for_my_custom_macro_impl) </pre>
</div> </div> <hr style="height: 1px; background-color: black; border: none;">This section provides useful commands and information to help debug issues that may arise during the Bzlmod migration.
Override version - Not rarely it happens that upgrading the version of a dependency causes troubles. Bzlmod could change the version of the dependency due to the MVS algorithm. In order to use the same or similar version as it was in the WORKSPACE, override it with single_version_override. Note that this is useful for debugging differences between WORKSPACE and Bzlmod, but you shouldn't rely on this feature in the long term.
single_version_override(module_name = "{dep_name}", version = "{version}")
Use bazel mod command.
Check the version of a specified repo with show_repo
command. For example:
bazel mod show_repo @rules_python
Check information about a module extension with the show_extension
command. For example:
bazel mod show_extension @rules_python//python/extensions:pip.bzl%pip
Use vendor mode to create a local copy of a repo when you want to monitor or control the source of the repo. For example:
bazel vendor --enable_bzlmod --vendor_dir=vendor_src --repo=@protobuf
This file is updated with each run of the migration script or it's generated
from scratch if it's the first run or if the --i
flag is used. The report contains:
Command for local testing.
List of direct dependencies (at least the ones which are directly used in the project).
For each dependency, a drop-down menu for checking where the repository was
declared in the WORKSPACE file, which is particularly useful for the
debugging. You can see it as:
For each dependency, how it was implemented in MODULE.bazel file. From the
earlier Migration Example, that would look as:
Bazel module Dependency - Migration of rules_python
perfect name match if it finds
it. In case of an error, you can double check if the name was correctly
added.Python extension - Migration of my_python_deps
Maven extension - Migration of org.antlr (px_deps):
Go extension - Migration of org_golang_x_net
go.mod. If
go.mod and go.sum are not available, go module is added directly
to the MODULE.bazel file.gazelle_override is used for adding specific directives.If you would like to contribute, do so by creating an Issue or PR at bazel-central-registry.