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:
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”, )
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”, ], )
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”, )
python = use_extension(“@rules_python//python/extensions:python.bzl”, “python”) python.defaults(python_version = “3.11”) python.toolchain(python_version = “3.11”)
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”, ], )
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” )
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”, )
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”, )
my_custom_macro( name = “my_custom_repo”, )
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)
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.