> ## Documentation Index
> Fetch the complete documentation index at: https://site.aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Adopting Bazel's new package manager

> Simplify Bazel package management with the new \&quot;bzlmod\&quot; feature for easier dependency handling and improved user experience

export const BlogPost = ({title, date, authors, tags, image, children}) => {
  const tagList = tags ? tags.split(", ").filter(Boolean) : [];
  const tagSlug = t => t.toLowerCase().replace(/&/g, "").replace(/\+/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
  const formattedDate = date ? new Date(date + "T00:00:00").toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
    day: "numeric"
  }) : "";
  return <section className="w-full flex justify-center px-4 py-12 md:py-16">
      <div style={{
    maxWidth: "800px",
    width: "100%"
  }}>
        {image && (typeof image === "string" ? <img noZoom src={image} alt={title} className="w-full rounded-xl mb-8" style={{
    maxHeight: "400px",
    objectFit: "cover"
  }} /> : <div className="blog-post-hero-image">{image}</div>)}
        <h1 className="text-3xl md:text-4xl font-bold text-zinc-900 dark:text-white">
          {title}
        </h1>
        <div className="flex flex-wrap items-center gap-3 mt-4 text-sm text-zinc-500 dark:text-zinc-400">
          {authors && <span>{authors}</span>}
          {authors && formattedDate && <span>·</span>}
          {formattedDate && <span>{formattedDate}</span>}
        </div>
        {tagList.length > 0 && <div className="flex flex-wrap gap-2 mt-3">
            {tagList.map(tag => <a key={tag} href={"/blog/tags/" + tagSlug(tag)} className="px-2 py-0.5 rounded-full text-xs bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 hover:bg-blue-100 dark:hover:bg-blue-900/40 hover:text-blue-700 dark:hover:text-blue-300 transition">
                {tag}
              </a>)}
          </div>}
        <hr className="my-8 border-zinc-200 dark:border-zinc-700" />
        <div className="prose dark:prose-invert max-w-none">{children}</div>
      </div>
    </section>;
};

export const MarketingPage = () => <div className="marketing-page-marker" style={{
  display: "none"
}} />;

export const Section = ({children, className = "", gray = false, dark = false, id}) => <section id={id} className={`w-full flex justify-center px-4 py-16 md:py-24 ${gray ? "bg-gray-50 dark:bg-zinc-900" : dark ? "bg-zinc-900 dark:bg-zinc-950" : ""} ${className}`}>
    <div className="w-full" style={{
  maxWidth: "1140px"
}}>
      {children}
    </div>
  </section>;

<MarketingPage />

<BlogPost title="Adopting Bazel's new package manager" date="2021-12-19" authors="Alex Eagle" tags="Bazel, Migration">
  <img noZoom src="https://mintcdn.com/aspectbuild/x1L7Iep716jCyJVo/images/blog/hashnode/hn-84079ecc94.jpeg?fit=max&auto=format&n=x1L7Iep716jCyJVo&q=85&s=dc0a7ccdb49c09b38dd83767871e2ceb" alt="" className="blog-post-cover" width="1600" height="1064" data-path="images/blog/hashnode/hn-84079ecc94.jpeg" />

  Bazel packages (called "modules") have historically been distributed with a long "WORKSPACE snippet", which required users to install and configure the module and *also* its dependencies. This caused a lot of headache for users, since the first declaration of some dependency wins, and so a wrong order of some transitive initialization code results in baffling errors which can be traced back (often with significant effort) to a root cause of version skew.

  As a result, rules authors had to be very careful about taking dependencies. To ensure an easier user experience, rules\_nodejs has always refused to add any dependencies at all, even on common modules like bazel-skylib.

  Yun and Xùdōng from the Bazel team at Google have been hard at work on fixing this, in a new feature called "bzlmod". The problem has actually had a few false starts in the past (the Bazel "Federation" was one) so it's awesome that this is nearly ready for adoption.

  You can read about the design of the feature in the [Bzlmod User Guide](https://docs.bazel.build/versions/main/bzlmod.html) so I won't repeat that here. Instead we'll just dive into how you can use it!

  ## What it looks like

  As an example, I'll use our SWC rule from [rules\_swc](https://github.com/aspect-build/rules_swc/blob/main/README.md) which runs a super-fast JavaScript/TypeScript transpiler written in Rust.

  If you use this rule today, there's a complex bunch of code to copy-paste into your project's `WORKSPACE` file, as illustrated by the install documentation on a release: [https://github.com/aspect-build/rules\_swc/releases/tag/v0.2.1](https://github.com/aspect-build/rules_swc/releases/tag/v0.2.1)

  Not only is that code that every user of the rule has to maintain, but all there's that headache mentioned before: this code interacts with other install code the user copied into that file. rules\_swc depends on a nodejs toolchain, a rust binding, a bunch of npm packages, bazel-skylib, and Aspect's bazel-lib of helper functions. That graph is pretty complex to leak through to the end-user!

  Under bzlmod, you can depend on rules\_swc with just one line in your `MODULE.bazel` file:

  ```plaintext theme={null}
  bazel_dep(name = "aspect_rules_swc", version = "0.2.0")
  ```

  The [example repo](https://github.com/aspect-build/bazel-examples/tree/e2d805683afdfcc1747621e7e9fc80b4ad71b6bb/bzlmod) shows that an swc target works correctly, using [MODULE.bazel](https://github.com/aspect-build/bazel-examples/blob/e2d805683afdfcc1747621e7e9fc80b4ad71b6bb/bzlmod/MODULE.bazel) to declare the dependencies.

  ## Kicking the tires yourself

  First, you'll need to use Bazel 5.0 or greater. As of this writing, you write this in your `.bazelversion` file:

  ```plaintext theme={null}
  5.0.0rc3
  ```

  > Follow [https://github.com/bazelbuild/bazel/issues/14013](https://github.com/bazelbuild/bazel/issues/14013) to find out when 5.0.0 final has shipped.

  This should update your local Bazel version. If it doesn't, your install is tied to one version, which you should fix following [https://docs.bazel.build/versions/main/install-bazelisk.html](https://docs.bazel.build/versions/main/install-bazelisk.html).

  Next you need to opt-in to the bzlmod feature. Add this to your `.bazelrc` file:

  ```plaintext theme={null}
  common --experimental_enable_bzlmod
  ```

  If you run `bazel info` now, you'll immediately get an error that you must create a `MODULE.bazel` file in the repository root, next to WORKSPACE. This file contains a syntactic subset Starlark, similar to `BUILD.bazel` files.

  If you want to create your own registry, you'll probably start by forking bazelbuild/bazel-central-registry. You'll then want to use the `--registry` flag, note that the value has to be a raw github server.

  For this example, I'll add Aspect's registry to `.bazelrc` with the line

  ```plaintext theme={null}
  common --registry=https://raw.githubusercontent.com/aspect-build/bazel-central-registry/main/
  ```

  > Note, `main` is a floating reference there. If you're pushing commits to your registry, you'll find that GitHub's CDN has too long of a Time-to-live, and your edits won't show up. Replace `main` with a commit SHA to fix this.

  If you add a dependency to your `MODULE.bazel`, for example

  ```plaintext theme={null}
  bazel_dep(name = "aspect_bazel_lib", version = "0.3.0")
  ```

  and do a build, you'll find there's now an external repository with that name and version in the external folder in your output\_base. (Look in `$(bazel info output_base)/external`)

  You can have a mix of dependencies declared in `WORKSPACE` and in `MODULE.bazel`. That's nice so you can do the migration one package at a time.

  However in practice you'll probably find many modules you depend on which aren't present on the registry at all. You'll have to bug their authors to add a MODULE.bazel file in their repo and publish to the registry. You could also contribute this yourself; see the next section.

  ## As a Rule Author

  If you write your own rules, you'll have to interact with bzlmod as a publisher too.

  You'll probably start with a local clone of the registry. The bazel server process caches the fetches from the registry (even if you use a `file:///` uri, sadly). So while testing your registration, you'll have to `bazel shutdown` before every bazel command.

  In your clone of `bazel-central-registry`, you can run the wizard `./tools/add_module.py`. This will prompt you for the info it needs. Delete any cruft (as of writing, it creates temp .json files in the working directory) and commit and push changes. You can push them to your own fork of the registry before making a PR to the upstream. Note that the BCR presubmit tests will only work when you open that PR.

  It's common to need patches on the upstream rule, at least to start with. Create it with a command like `git diff > ../bcr/modules/my_module/0.1.0/patches/bzlmod.patch` (or `git show` if the changes are already committed). You'll have to create a subresource integrity hash of the content of that patch, with a command like

  ```shell theme={null}
  shasum -a 256 modules/aspect_rules_js/0.3.0/patches/bzlmod.patch | awk '{print $1}' | xxd -r -p | base64`
  ```

  Be careful, if the patch file contains edits to the project's `WORKSPACE` it will fail to apply, because at the time bzlmod applies it, the WORKSPACE file is auto-generated 2 lines of code instead of what came from your rules repo. Then register the patch in your `source.json` like other examples in BCR.

  Things that will need to be patched or changed include:

  * **toolchain registration**: Extensions can't call native modules (they are evaluated on a different thread for performance). bzlmod has a different syntax for this anyhow, so repository rules shouldn't need to register toolchains. See [this patch on rules\_sh](https://github.com/aspect-build/bazel-central-registry/blob/main/modules/rules_sh/0.2.0/patches/add_module_extension.patch#L68-L82) as the example I followed.

  * **fixed repository names**: bzlmod maps the repositories in order to namespace them for the strict visibility feature. If your rules expect to create an external repository `@foo` and then use `@foo//some:target` in a BUILD file or as a default for an attribute, you'll find that repo doesn't exist. Or in my case I had BUILD files assuming `@foo//:foo` target would exist, and needed to make it `@foo//:pkg` so the target is predictable without knowing the repository name.

  * **result of one repository rule used by another**: [https://github.com/bazelbuild/bazel/issues/14445](https://github.com/bazelbuild/bazel/issues/14445) - I had to refactor rules not to require this feature

  ## More resources

  By default, the registry at [https://github.com/bazelbuild/bazel-central-registry](https://github.com/bazelbuild/bazel-central-registry) is used to discover Bazel modules. Other registries may be created, in particular large companies will likely run a private registry for their own modules.

  Yun created a bunch of examples you can reference: [https://github.com/meteorcloudy/bzlmod-examples](https://github.com/meteorcloudy/bzlmod-examples).

  Open issues with bzlmod: [https://github.com/bazelbuild/bazel/issues?q=is%3Aopen+is%3Aissue+project%3Abazelbuild%2Fbazel%2F9](https://github.com/bazelbuild/bazel/issues?q=is%3Aopen+is%3Aissue+project%3Abazelbuild%2Fbazel%2F9)

  There's a listing of resources, including the BazelCon talk: [https://docs.bazel.build/versions/main/bzlmod.html#external-links](https://docs.bazel.build/versions/main/bzlmod.html#external-links)
</BlogPost>
