New documentation for external deps
Rewrote the "external dependencies" and "Bzlmod" pages, organizing them into a subcategory of pages on external dependencies instead.

PiperOrigin-RevId: 506646517
Change-Id: Ib3f1d6fb8c33c06e723aeef2eb0a5b7a223cc487
diff --git a/site/en/_book.yaml b/site/en/_book.yaml
index f2466d5..e6d10c5 100644
--- a/site/en/_book.yaml
+++ b/site/en/_book.yaml
@@ -108,10 +108,6 @@
         path: /build/style-guide
       - title: Share variables
         path: /build/share-variables
-      - title: External dependencies
-        path: /build/external
-      - title: Manage dependencies with Bzlmod
-        path: /build/bzlmod
       - title: Recommended rules
         path: /community/recommended-rules
       - heading: Running Bazel
@@ -125,6 +121,17 @@
         path: /run/scripts
       - title: Client/server implementation
         path: /run/client-server
+      - heading: External dependencies
+      - title: Overview
+        path: /external/overview
+      - title: Bazel modules
+        path: /external/module
+      - title: Bazel registries
+        path: /external/registry
+      - title: Module extensions
+        path: /external/extension
+      - title: Advanced topics
+        path: /external/advanced
       - heading: Querying your build
       - title: Query quickstart
         path: /query/quickstart
diff --git a/site/en/about/roadmap.md b/site/en/about/roadmap.md
index ff8b0c3..e7b8568 100644
--- a/site/en/about/roadmap.md
+++ b/site/en/about/roadmap.md
@@ -20,7 +20,7 @@
 
 ### Bzlmod: external dependency management system
 
-[Bzlmod](https://bazel.build/build/bzlmod) automatically resolves transitive dependencies, allowing projects to scale while staying fast and resource-efficient. Introduced experimentally in Bazel 5.0, Bzlmod will be generally available and  provide a solution for the [diamond dependency problem](https://docs.google.com/document/d/1moQfNcEIttsk6vYanNKIy3ZuK53hQUFq1b1r0rmsYVg/edit#heading=h.lgyp7ubwxmjc).
+[Bzlmod](https://bazel.build/external/overview#bzlmod) automatically resolves transitive dependencies, allowing projects to scale while staying fast and resource-efficient. Introduced experimentally in Bazel 5.0, Bzlmod will be generally available and  provide a solution for the [diamond dependency problem](https://docs.google.com/document/d/1moQfNcEIttsk6vYanNKIy3ZuK53hQUFq1b1r0rmsYVg/edit#heading=h.lgyp7ubwxmjc).
 
 *   Bzlmod goes from ‘experimental’ to ‘generally available’
 *   [Bzlmod Migration Guide](https://docs.google.com/document/d/1JtXIVnXyFZ4bmbiBCr5gsTH4-opZAFf5DMMb-54kES0/edit?usp=gmail) provides tools, scripts, and documentation to teams looking to adopt Bzlmod
diff --git a/site/en/build/bzlmod.md b/site/en/build/bzlmod.md
deleted file mode 100644
index a2a2815..0000000
--- a/site/en/build/bzlmod.md
+++ /dev/null
@@ -1,445 +0,0 @@
-Project: /_project.yaml
-Book: /_book.yaml
-
-# Manage external dependencies with Bzlmod
-
-{% include "_buttons.html" %}
-
-*Bzlmod* is the codename of the new [external dependency](/docs/external) system
-introduced in Bazel 5.0. It was introduced to address several pain points of the
-old system that couldn't feasibly be fixed incrementally; see the
-[Problem Statement section of the original design doc](https://docs.google.com/document/d/1moQfNcEIttsk6vYanNKIy3ZuK53hQUFq1b1r0rmsYVg/edit#heading=h.xxnnwabymk1v){: .external}
-for more details.
-
-In Bazel 5.0, Bzlmod is not turned on by default; the flag
-`--experimental_enable_bzlmod` needs to be specified for the following to take
-effect. As the flag name suggests, this feature is currently *experimental*;
-APIs and behaviors may change until the feature officially launches.
-
-To migrate your project to Bzlmod, follow the [Bzlmod Migration Guide](https://docs.google.com/document/d/1JtXIVnXyFZ4bmbiBCr5gsTH4-opZAFf5DMMb-54kES0/edit?usp=sharing).
-You can also find example Bzlmod usages in the [examples](https://github.com/bazelbuild/examples/tree/main/bzlmod) repository.
-
-## Bazel Modules {:#modules}
-
-The old `WORKSPACE`-based external dependency system is centered around
-*repositories* (or *repos*), created via *repository rules* (or *repo rules*).
-While repos are still an important concept in the new system, *modules* are the
-core units of dependency.
-
-A *module* is essentially a Bazel project that can have multiple versions, each
-of which publishes metadata about other modules that it depends on. This is
-analogous to familiar concepts in other dependency management systems: a Maven
-*artifact*, an npm *package*, a Cargo *crate*, a Go *module*, etc.
-
-A module simply specifies its dependencies using `name` and `version` pairs,
-instead of specific URLs in `WORKSPACE`. The dependencies are then looked up in
-a [Bazel registry](#registries); by default, the
-[Bazel Central Registry](#bazel-central-registry). In your workspace, each
-module then gets turned into a repo.
-
-### MODULE.bazel {:#module-bazel}
-
-Every version of every module has a `MODULE.bazel` file declaring its
-dependencies and other metadata. Here's 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")
-```
-
-The `MODULE.bazel` file should be located at the root of the workspace directory
-(next to the `WORKSPACE` file). Unlike with the `WORKSPACE` file, you don't need
-to specify your *transitive* dependencies; instead, you should only specify
-*direct* dependencies, and the `MODULE.bazel` files of your dependencies are
-processed to discover transitive dependencies automatically.
-
-The `MODULE.bazel` file is similar to `BUILD` files as it doesn't support any
-form of control flow; it additionally forbids `load` statements. The directives
-`MODULE.bazel` files support are:
-
-*   [`module`](/rules/lib/globals#module), to specify metadata
-    about the current module, including its name, version, and so on;
-*   [`bazel_dep`](/rules/lib/globals#bazel_dep), to specify direct
-    dependencies on other Bazel modules;
-*   Overrides, which can only be used by the root module (that is, not by a
-    module which is being used as a dependency) to customize the behavior of a
-    certain direct or transitive dependency:
-    *   [`single_version_override`](/rules/lib/globals#single_version_override)
-    *   [`multiple_version_override`](/rules/lib/globals#multiple_version_override)
-    *   [`archive_override`](/rules/lib/globals#archive_override)
-    *   [`git_override`](/rules/lib/globals#git_override)
-    *   [`local_path_override`](/rules/lib/globals#local_path_override)
-*   Directives related to [module extensions](#module-extensions):
-    *   [`use_extension`](/rules/lib/globals#use_extension)
-    *   [`use_repo`](/rules/lib/globals#use_repo)
-
-### Version format {:#version-format}
-
-Bazel has a diverse ecosystem and projects use various versioning schemes. The
-most popular by far is [SemVer](https://semver.org){: .external}, but there are
-also prominent projects using different schemes such as
-[Abseil](https://github.com/abseil/abseil-cpp/releases){: .external}, whose
-versions are date-based, for example `20210324.2`).
-
-For this reason, Bzlmod adopts a more relaxed version of the SemVer spec. The
-differences include:
-
-*   SemVer prescribes that the "release" part of the version must consist of 3
-    segments: `MAJOR.MINOR.PATCH`. In Bazel, this requirement is loosened so
-    that any number of segments is allowed.
-*   In SemVer, each of the segments in the "release" part must be digits only.
-    In Bazel, this is loosened to allow letters too, and the comparison
-    semantics match the "identifiers" in the "prerelease" part.
-*   Additionally, the semantics of major, minor, and patch version increases are
-    not enforced. (However, see [compatibility level](#compatibility-level) for
-    details on how we denote backwards compatibility.)
-
-Any valid SemVer version is a valid Bazel module version. Additionally, two
-SemVer versions `a` and `b` compare `a < b` iff the same holds when they're
-compared as Bazel module versions.
-
-### Version resolution {:#version-resolution}
-
-The diamond dependency problem is a staple in the versioned dependency
-management space. Suppose you have the following dependency graph:
-
-```
-       A 1.0
-      /     \
-   B 1.0    C 1.1
-     |        |
-   D 1.0    D 1.1
-```
-
-Which version of D should be used? To resolve this question, Bzlmod uses the
-[Minimal Version Selection](https://research.swtch.com/vgo-mvs){: .external}
-(MVS) algorithm introduced in the Go module system. MVS assumes that all new
-versions of a module are backwards compatible, and thus simply picks the highest
-version specified by any dependent (D 1.1 in our example). It's called "minimal"
-because D 1.1 here is the *minimal* version that could satisfy our requirements;
-even if D 1.2 or newer exists, we don't select them. This has the added benefit
-that the version selection is *high-fidelity* and *reproducible*.
-
-Version resolution is performed locally on your machine, not by the registry.
-
-### Compatibility level {:#compatibility-level}
-
-Note that MVS's assumption about backwards compatibility is feasible because it
-simply treats backwards incompatible versions of a module as a separate module.
-In terms of SemVer, that means A 1.x and A 2.x are considered distinct modules,
-and can coexist in the resolved dependency graph. This is, in turn, made
-possible by the fact that the major version is encoded in the package path in
-Go, so there aren't any compile-time or linking-time conflicts.
-
-In Bazel, we don't have such guarantees. Thus we need a way to denote the "major
-version" number in order to detect backwards incompatible versions. This number
-is called the *compatibility level*, and is specified by each module version in
-its `module()` directive. With this information in hand, we can throw an error
-when we detect that versions of the same module with different compatibility
-levels exist in the resolved dependency graph.
-
-### Repository names {:#repository-names}
-
-In Bazel, every external dependency has a repository name. Sometimes, the same
-dependency might be used via different repository names (for example, both
-`@io_bazel_skylib` and `@bazel_skylib` mean
-[Bazel skylib](https://github.com/bazelbuild/bazel-skylib){: .external}), or the same
-repository name might be used for different dependencies in different projects.
-
-In Bzlmod, repositories can be generated by Bazel modules and
-[module extensions](#module-extensions). To resolve repository name conflicts,
-we are embracing the [repository mapping](/docs/external#shadowing-dependencies)
-mechanism in the new system. Here are two important concepts:
-
-*   **Canonical repository name**: The globally unique repository name for each
-    repository. This will be the directory name the repository lives in.
-    <br>It's constructed as follows (**Warning**: the canonical name format is
-    not an API you should depend on, it's subject to change at any time):
-
-    *   For Bazel module repos: `{{ "<var>" }}module_name{{ "</var>" }}~{{ "<var>" }}version{{ "</var>" }}`
-        <br> (<b>Example</b>. `@bazel_skylib~1.0.3`)
-    *   For module extension repos: `{{ "<var>" }}module_name{{ "</var>" }}~{{ "<var>" }}version{{ "</var>" }}~{{ "<var>" }}extension_name{{ "</var>" }}~{{ "<var>" }}repo_name{{ "</var>" }}`
-        <br>(<b>Example</b>. `@rules_cc~0.0.1~cc_configure~local_config_cc`)
-
-*   **Apparent repository name**: The repository name to be used in the `BUILD` and
-    `.bzl` files within a repo. The same dependency could have different apparent
-    names in different repos.
-    <br>It's determined as follows:
-
-    *   For Bazel module repos: `{{ "<var>" }}module_name{{ "</var>" }}` by
-        default, or the name specified by the `repo_name` attribute in
-        [`bazel_dep`](/rules/lib/globals#bazel_dep).
-    *   For module extension repos: repository name introduced via
-        [`use_repo`](/rules/lib/globals#use_repo).
-
-Every repository has a repository mapping dictionary of its direct dependencies,
-which is a map from the apparent repository name to the canonical repository name.
-We use the repository mapping to resolve the repository name when constructing a
-label. Note that, there is no conflict of canonical repository names, and the
-usages of apparent repository names can be discovered by parsing the `MODULE.bazel`
-file, therefore conflicts can be easily caught and resolved without affecting
-other dependencies.
-
-### Strict deps {:#strict-deps}
-
-The new dependency specification format allows us to perform stricter checks. In
-particular, we now enforce that a module can only use repos created from its
-direct dependencies. This helps prevent accidental and hard-to-debug breakages
-when something in the transitive dependency graph changes.
-
-Strict deps is implemented based on
-[repository mapping](/docs/external#shadowing-dependencies). Basically, the
-repository mapping for each repo contains all of its *direct dependencies*, any
-other repository is not visible. Visible dependencies for each repository are
-determined as follows:
-
-*   A Bazel module repo can see all repos introduced in the `MODULE.bazel` file
-    via [`bazel_dep`](/rules/lib/globals#bazel_dep) and
-    [`use_repo`](/rules/lib/globals#use_repo).
-*   A module extension repo can see all visible dependencies of the module that
-    provides the extension, plus all other repos generated by the same module
-    extension.
-
-## Registries {:#registries}
-
-Bzlmod discovers dependencies by requesting their information from Bazel
-*registries*. A Bazel registry is simply a database of Bazel modules. The only
-supported form of registries is an [*index registry*](#index-registry), which is
-a local directory or a static HTTP server following a specific format. In the
-future, we plan to add support for *single-module registries*, which are simply
-git repos containing the source and history of a project.
-
-### Index registry {:#index-registry}
-
-An index registry is a local directory or a static HTTP server containing
-information about a list of modules, including their homepage, maintainers, the
-`MODULE.bazel` file of each version, and how to fetch the source of each
-version. Notably, it does *not* need to serve the source archives itself.
-
-An index registry must follow the format below:
-
-*   `/bazel_registry.json`: A JSON file containing metadata for the registry like:
-    * `mirrors`, specifying the list of mirrors to use for source archives.
-    * `module_base_path`, specifying the base path for modules with
-      `local_repository` type in the `source.json` file.
-*   `/modules`: A directory containing a subdirectory for each module in this
-    registry.
-*   `/modules/$MODULE`: A directory containing a subdirectory for each version
-    of this module, as well as the following file:
-    *   `metadata.json`: A JSON file containing information about the module,
-        with the following fields:
-        *   `homepage`: The URL of the project's homepage.
-        *   `maintainers`: A list of JSON objects, each of which corresponds to
-            the information of a maintainer of the module *in the registry*.
-            Note that this is not necessarily the same as the *authors* of the
-            project.
-        *   `versions`: A list of all the versions of this module to be found in
-            this registry.
-        *   `yanked_versions`: A list of *yanked* versions of this module. This
-            is currently a no-op, but in the future, yanked versions will be
-            skipped or yield an error.
-*   `/modules/$MODULE/$VERSION`: A directory containing the following files:
-    *   `MODULE.bazel`: The `MODULE.bazel` file of this module version.
-    *   `source.json`: A JSON file containing information on how to fetch the
-        source of this module version.
-      * The default type is "archive" with the following fields:
-          *   `url`: The URL of the source archive.
-          *   `integrity`: The
-              [Subresource Integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description){: .external}
-              checksum of the archive.
-          *   `strip_prefix`: A directory prefix to strip when extracting the
-              source archive.
-          *   `patches`: A list of strings, each of which names a patch file to
-              apply to the extracted archive. The patch files are located under
-              the `/modules/$MODULE/$VERSION/patches` directory.
-          *   `patch_strip`: Same as the `--strip` argument of Unix patch.
-      * The type can be changed to use a local path with these fields:
-          *   `type`: `local_path`
-          *   `path`: The local path to the repo, calculated as following:
-              * If path is an absolute path, will be used as it is.
-              * If path is a relative path and `module_base_path` is an absolute path,
-                path is resolved to `<module_base_path>/<path>`
-              * If path and `module_base_path` are both relative paths, path is
-                resolved to `<registry_path>/<module_base_path>/<path>`.
-                Registry must be hosted locally and used by `--registry=file://<registry_path>`.
-                Otherwise, Bazel will throw an error.
-    *   `patches/`: An optional directory containing patch files, only used when `source.json` has "archive" type.
-
-### Bazel Central Registry {:#bazel-central-registry}
-
-Bazel Central Registry (BCR) is an index registry located at
-[bcr.bazel.build](https://bcr.bazel.build){: .external}. Its contents
-are backed by the GitHub repo
-[`bazelbuild/bazel-central-registry`](https://github.com/bazelbuild/bazel-central-registry){: .external}.
-
-The BCR is maintained by the Bazel community; contributors are welcome to submit
-pull requests. See
-[Bazel Central Registry Policies and Procedures](https://docs.google.com/document/d/1ReuBBp4EHnsuvcpfXM6ITDmP2lrOu8DGlePMUKvDnXM/edit?usp=sharing){: .external}.
-
-In addition to following the format of a normal index registry, the BCR requires
-a `presubmit.yml` file for each module version
-(`/modules/$MODULE/$VERSION/presubmit.yml`). This file specifies a few essential
-build and test targets that can be used to sanity-check the validity of this
-module version, and is used by the BCR's CI pipelines to ensure interoperability
-between modules in the BCR.
-
-### Selecting registries {:#selecting-registries}
-
-The repeatable Bazel flag `--registry` can be used to specify the list of
-registries to request modules from, so you could set up your project to fetch
-dependencies from a third-party or internal registry. Earlier registries take
-precedence. For convenience, you can put a list of `--registry` flags in the
-`.bazelrc` file of your project.
-
-Note: If your registry is hosted on GitHub (for example, as a fork of
-`bazelbuild/bazel-central-registry`) then your `--registry` value needs a raw
-GitHub address under `raw.githubusercontent.com`. For example, on the `main`
-branch of the `my-org` fork, you would set
-`--registry=https://raw.githubusercontent.com/my-org/bazel-central-registry/main/`.
-
-## Module Extensions {:#module-extensions}
-
-Module extensions allow you to extend the module system by reading input data
-from modules across the dependency graph, performing necessary logic to resolve
-dependencies, and finally creating repos by calling repo rules. They are similar
-in function to today's `WORKSPACE` macros, but are more suited in the world of
-modules and transitive dependencies.
-
-Module extensions are defined in `.bzl` files, just like repo rules or
-`WORKSPACE` macros. They're not invoked directly; rather, each module can
-specify pieces of data called *tags* for extensions to read. Then, after module
-version resolution is done, module extensions are run. Each extension is run
-once after module resolution (still before any build actually happens), and
-gets to read all the tags belonging to it across the entire dependency graph.
-
-```
-          [ A 1.1                ]
-          [   * maven.dep(X 2.1) ]
-          [   * maven.pom(...)   ]
-              /              \
-   bazel_dep /                \ bazel_dep
-            /                  \
-[ B 1.2                ]     [ C 1.0                ]
-[   * maven.dep(X 1.2) ]     [   * maven.dep(X 2.1) ]
-[   * maven.dep(Y 1.3) ]     [   * cargo.dep(P 1.1) ]
-            \                  /
-   bazel_dep \                / bazel_dep
-              \              /
-          [ D 1.4                ]
-          [   * maven.dep(Z 1.4) ]
-          [   * cargo.dep(Q 1.1) ]
-```
-
-In the example dependency graph above, `A 1.1` and `B 1.2` etc are Bazel modules;
-you can think of each one as a `MODULE.bazel` file. Each module can specify some
-tags for module extensions; here some are specified for the extension "maven",
-and some are specified for "cargo". When this dependency graph is finalized (for
-example, maybe `B 1.2` actually has a `bazel_dep` on `D 1.3` but got upgraded to
-`D 1.4` due to `C`), the extensions "maven" is run, and it gets to read all the
-`maven.*` tags, using information therein to decide which repos to create.
-Similarly for the "cargo" extension.
-
-### Extension usage {:#extension-usage}
-
-Extensions are hosted in Bazel modules themselves, so to use an extension in
-your module, you need to first add a `bazel_dep` on that module, and then call
-the [`use_extension`](/rules/lib/globals#use_extension) built-in
-function to bring it into scope. Consider the following example, a snippet from
-a `MODULE.bazel` file to use a hypothetical "maven" extension defined in the
-`rules_jvm_external` module:
-
-```python
-bazel_dep(name = "rules_jvm_external", version = "1.0")
-maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
-```
-
-After bringing the extension into scope, you can then use the dot-syntax to
-specify tags for it. Note that the tags need to follow the schema defined by the
-corresponding *tag classes* (see [extension definition](#extension-definition)
-below). Here's an example specifying some `maven.dep` and `maven.pom` tags.
-
-```python
-maven.dep(coord="org.junit:junit:3.0")
-maven.dep(coord="com.google.guava:guava:1.2")
-maven.pom(pom_xml="//:pom.xml")
-```
-
-If the extension generates repos that you want to use in your module, use the
-[`use_repo`](/rules/lib/globals#use_repo) directive to declare
-them. This is to satisfy the strict deps condition and avoid local repo name
-conflict.
-
-```python
-use_repo(
-    maven,
-    "org_junit_junit",
-    guava="com_google_guava_guava",
-)
-```
-
-The repos generated by an extension are part of its API, so from the tags you
-specified, you should know that the "maven" extension is going to generate a
-repo called "org_junit_junit", and one called "com_google_guava_guava". With
-`use_repo`, you can optionally rename them in the scope of your module, like to
-"guava" here.
-
-### Extension definition {:#extension-definition}
-
-Module extensions are defined similarly to repo rules, using the
-[`module_extension`](/rules/lib/globals#module_extension) function.
-Both have an implementation function; but while repo rules have a number of
-attributes, module extensions have a number of
-[`tag_class`es](/rules/lib/globals#tag_class), each of which has a
-number of attributes. The tag classes define schemas for tags used by this
-extension. Continuing our example of the hypothetical "maven" extension above:
-
-```python
-# @rules_jvm_external//:extensions.bzl
-maven_dep = tag_class(attrs = {"coord": attr.string()})
-maven_pom = tag_class(attrs = {"pom_xml": attr.label()})
-maven = module_extension(
-    implementation=_maven_impl,
-    tag_classes={"dep": maven_dep, "pom": maven_pom},
-)
-```
-
-These declarations make it clear that `maven.dep` and `maven.pom` tags can be
-specified, using the attribute schema defined above.
-
-The implementation function is similar to a `WORKSPACE` macro, except that it
-gets a [`module_ctx`](/rules/lib/module_ctx) object, which grants
-access to the dependency graph and all pertinent tags. The implementation
-function should then call repo rules to generate repos:
-
-```python
-# @rules_jvm_external//:extensions.bzl
-load("//:repo_rules.bzl", "maven_single_jar")
-def _maven_impl(ctx):
-  coords = []
-  for mod in ctx.modules:
-    coords += [dep.coord for dep in mod.tags.dep]
-  output = ctx.execute(["coursier", "resolve", coords])  # hypothetical call
-  repo_attrs = process_coursier(output)
-  [maven_single_jar(**attrs) for attrs in repo_attrs]
-```
-
-In the example above, we go through all the modules in the dependency graph
-(`ctx.modules`), each of which is a
-[`bazel_module`](/rules/lib/bazel_module) object whose `tags` field
-exposes all the `maven.*` tags on the module. Then we invoke the CLI utility
-Coursier to contact Maven and perform resolution. Finally, we use the resolution
-result to create a number of repos, using the hypothetical `maven_single_jar`
-repo rule.
-
-## External links
-
-*   [Bazel External Dependencies Overhaul](https://docs.google.com/document/d/1moQfNcEIttsk6vYanNKIy3ZuK53hQUFq1b1r0rmsYVg/edit){: .external}
-    (original Bzlmod design doc)
-*   [Bazel Central Registry Policies and Procedures](https://docs.google.com/document/d/1ReuBBp4EHnsuvcpfXM6ITDmP2lrOu8DGlePMUKvDnXM/edit?usp=sharing){: .external}
-*   [Bazel Central Registry GitHub repo](https://github.com/bazelbuild/bazel-central-registry){: .external}
-*   [BazelCon 2021 talk on Bzlmod](https://www.youtube.com/watch?v=TxOCKtU39Fs){: .external}
diff --git a/site/en/build/external.md b/site/en/build/external.md
deleted file mode 100644
index 6d7292d..0000000
--- a/site/en/build/external.md
+++ /dev/null
@@ -1,370 +0,0 @@
-Project: /_project.yaml
-Book: /_book.yaml
-
-# Working with External Dependencies
-
-{% include "_buttons.html" %}
-
-Bazel can depend on targets from other projects. Dependencies from these other
-projects are called _external dependencies_.
-
-Note: Bazel 5.0 and newer has a new external dependency system, codenamed
-"Bzlmod", which renders a lot of the content on this page obsolete. See [Bzlmod
-user guide](/build/bzlmod) for more information.
-
-The `WORKSPACE` file (or `WORKSPACE.bazel` file) in the
-[workspace directory](/concepts/build-ref#workspace)
-tells Bazel how to get other projects' sources. These other projects can
-contain one or more `BUILD` files with their own targets. `BUILD` files within
-the main project can depend on these external targets by using their name from
-the `WORKSPACE` file.
-
-For example, suppose there are two projects on a system:
-
-```
-/
-  home/
-    user/
-      project1/
-        WORKSPACE
-        BUILD
-        srcs/
-          ...
-      project2/
-        WORKSPACE
-        BUILD
-        my-libs/
-```
-
-If `project1` wanted to depend on a target, `:foo`, defined in
-`/home/user/project2/BUILD`, it could specify that a repository named
-`project2` could be found at `/home/user/project2`. Then targets in
-`/home/user/project1/BUILD` could depend on `@project2//:foo`.
-
-The `WORKSPACE` file allows users to depend on targets from other parts of the
-filesystem or downloaded from the internet. It uses the same syntax as `BUILD`
-files, but allows a different set of rules called _repository rules_ (sometimes
-also known as _workspace rules_). Bazel comes with a few [built-in repository
-rules](/reference/be/workspace) and a set of [embedded Starlark repository
-rules](/rules/lib/repo/index). Users can also write [custom repository
-rules](/extending/repo) to get more complex behavior.
-
-## Supported types of external dependencies {:#types}
-
-A few basic types of external dependencies can be used:
-
-- [Dependencies on other Bazel projects](#bazel-projects)
-- [Dependencies on non-Bazel projects](#non-bazel-projects)
-- [Dependencies on external packages](#external-packages)
-
-### Depending on other Bazel projects {:#bazel-projects}
-
-If you want to use targets from a second Bazel project, you can
-use
-[`local_repository`](/reference/be/workspace#local_repository),
-[`git_repository`](/rules/lib/repo/git#git_repository)
-or [`http_archive`](/rules/lib/repo/http#http_archive)
-to symlink it from the local filesystem, reference a git repository or download
-it (respectively).
-
-For example, suppose you are working on a project, `my-project/`, and you want
-to depend on targets from your coworker's project, `coworkers-project/`. Both
-projects use Bazel, so you can add your coworker's project as an external
-dependency and then use any targets your coworker has defined from your own
-BUILD files. You would add the following to `my_project/WORKSPACE`:
-
-```python
-local_repository(
-    name = "coworkers_project",
-    path = "/path/to/coworkers-project",
-)
-```
-
-If your coworker has a target `//foo:bar`, your project can refer to it as
-`@coworkers_project//foo:bar`. External project names must be
-[valid workspace names](/rules/lib/globals#workspace).
-
-### Depending on non-Bazel projects {:#non-bazel-projects}
-
-Rules prefixed with `new_`, such as
-[`new_local_repository`](/reference/be/workspace#new_local_repository),
-allow you to create targets from projects that do not use Bazel.
-
-For example, suppose you are working on a project, `my-project/`, and you want
-to depend on your coworker's project, `coworkers-project/`. Your coworker's
-project uses `make` to build, but you'd like to depend on one of the .so files
-it generates. To do so, add the following to `my_project/WORKSPACE`:
-
-```python
-new_local_repository(
-    name = "coworkers_project",
-    path = "/path/to/coworkers-project",
-    build_file = "coworker.BUILD",
-)
-```
-
-`build_file` specifies a `BUILD` file to overlay on the existing project, for
-example:
-
-```python
-cc_library(
-    name = "some-lib",
-    srcs = glob(["**"]),
-    visibility = ["//visibility:public"],
-)
-```
-
-You can then depend on `@coworkers_project//:some-lib` from your project's
-`BUILD` files.
-
-### Depending on external packages {:#external-packages}
-
-#### Maven artifacts and repositories {:#maven-repositories}
-
-Use the ruleset [`rules_jvm_external`](https://github.com/bazelbuild/rules_jvm_external){: .external}
-to download artifacts from Maven repositories and make them available as Java
-dependencies.
-
-## Fetching dependencies {:#fetching-dependencies}
-
-By default, external dependencies are fetched as needed during `bazel build`. If
-you would like to prefetch the dependencies needed for a specific set of targets, use
-[`bazel fetch`](/reference/command-line-reference#commands).
-To unconditionally fetch all external dependencies, use
-[`bazel sync`](/reference/command-line-reference#commands).
-As fetched repositories are [stored in the output base](#layout), fetching
-happens per workspace.
-
-## Shadowing dependencies {:#shadowing-dependencies}
-
-Whenever possible, it is recommended to have a single version policy in your
-project. This is required for dependencies that you compile against and end up
-in your final binary. But for cases where this isn't true, it is possible to
-shadow dependencies. Consider the following scenario:
-
-myproject/WORKSPACE
-
-```python
-workspace(name = "myproject")
-
-local_repository(
-    name = "A",
-    path = "../A",
-)
-local_repository(
-    name = "B",
-    path = "../B",
-)
-```
-
-A/WORKSPACE
-
-```python
-workspace(name = "A")
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-http_archive(
-    name = "testrunner",
-    urls = ["https://github.com/testrunner/v1.zip"],
-    sha256 = "...",
-)
-```
-
-B/WORKSPACE
-
-```python
-workspace(name = "B")
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-http_archive(
-    name = "testrunner",
-    urls = ["https://github.com/testrunner/v2.zip"],
-    sha256 = "..."
-)
-```
-
-Both dependencies `A` and `B` depend on `testrunner`, but they depend on
-different versions of `testrunner`. There is no reason for these test runners to
-not peacefully coexist within `myproject`, however they will clash with each
-other since they have the same name. To declare both dependencies,
-update myproject/WORKSPACE:
-
-```python
-workspace(name = "myproject")
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-http_archive(
-    name = "testrunner-v1",
-    urls = ["https://github.com/testrunner/v1.zip"],
-    sha256 = "..."
-)
-http_archive(
-    name = "testrunner-v2",
-    urls = ["https://github.com/testrunner/v2.zip"],
-    sha256 = "..."
-)
-local_repository(
-    name = "A",
-    path = "../A",
-    repo_mapping = {"@testrunner" : "@testrunner-v1"}
-)
-local_repository(
-    name = "B",
-    path = "../B",
-    repo_mapping = {"@testrunner" : "@testrunner-v2"}
-)
-```
-
-This mechanism can also be used to join diamonds. For example if `A` and `B`
-had the same dependency but call it by different names, those dependencies can
-be joined in myproject/WORKSPACE.
-
-## Overriding repositories from the command line {:#overriding-repositories}
-
-To override a declared repository with a local repository from the command line,
-use the
-[`--override_repository`](/reference/command-line-reference#flag--override_repository)
-flag. Using this flag changes the contents of external repositories without
-changing your source code.
-
-For example, to override `@foo` to the local directory `/path/to/local/foo`,
-pass the `--override_repository=foo=/path/to/local/foo` flag.
-
-Some of the use cases include:
-
-* Debugging issues. For example, you can override a `http_archive` repository
-  to a local directory where you can make changes more easily.
-* Vendoring. If you are in an environment where you cannot make network calls,
-  override the network-based repository rules to point to local directories
-  instead.
-
-## Using proxies {:#using-proxies}
-
-Bazel will pick up proxy addresses from the `HTTPS_PROXY` and `HTTP_PROXY`
-environment variables and use these to download HTTP/HTTPS files (if specified).
-
-## Support for IPv6 {:#support-for-ipv6}
-
-On IPv6-only machines, Bazel will be able to download dependencies with
-no changes. On dual-stack IPv4/IPv6 machines, however, Bazel follows the same
-convention as Java: if IPv4 is enabled, IPv4 is preferred. In some situations,
-for example when IPv4 network is unable to resolve/reach external addresses,
-this can cause `Network unreachable` exceptions and build failures.
-In these cases, you can override Bazel's behavior to prefer IPv6
-by using [`java.net.preferIPv6Addresses=true` system property](https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html){: .external}.
-Specifically:
-
-* Use `--host_jvm_args=-Djava.net.preferIPv6Addresses=true`
-  [startup option](/docs/user-manual#startup-options),
-  for example by adding the following line in your
-  [`.bazelrc` file](/run/bazelrc):
-
-  `startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true`
-
-* If you are running Java build targets that need to connect to the internet
-  as well (integration tests sometimes needs that), also use
-  `--jvmopt=-Djava.net.preferIPv6Addresses=true`
-  [tool flag](/docs/user-manual#jvmopt), for example by having the
-  following line in your [`.bazelrc` file](/run/bazelrc):
-
-  `build --jvmopt=-Djava.net.preferIPv6Addresses`
-
-* If you are using
-  [rules_jvm_external](https://github.com/bazelbuild/rules_jvm_external){: .external},
-  for example, for dependency version resolution, also add
-  `-Djava.net.preferIPv6Addresses=true` to the `COURSIER_OPTS`
-  environment variable to [provide JVM options for Coursier](https://github.com/bazelbuild/rules_jvm_external#provide-jvm-options-for-coursier-with-coursier_opts){: .external}
-
-## Transitive dependencies {:#transitive-dependencies}
-
-Bazel only reads dependencies listed in your `WORKSPACE` file. If your project
-(`A`) depends on another project (`B`) which lists a dependency on a third
-project (`C`) in its `WORKSPACE` file, you'll have to add both `B`
-and `C` to your project's `WORKSPACE` file. This requirement can balloon the
-`WORKSPACE` file size, but limits the chances of having one library
-include `C` at version 1.0 and another include `C` at 2.0.
-
-## Caching of external dependencies {:#caching-external-dependencies}
-
-By default, Bazel will only re-download external dependencies if their
-definition changes. Changes to files referenced in the definition (such as patches
-or `BUILD` files) are also taken into account by bazel.
-
-To force a re-download, use `bazel sync`.
-
-## Layout {:#layout}
-
-External dependencies are all downloaded to a directory under the subdirectory
-`external` in the [output base](/remote/output-directories). In case of a
-[local repository](/reference/be/workspace#local_repository), a symlink is created
-there instead of creating a new directory.
-You can see the `external` directory by running:
-
-```posix-terminal
-ls $(bazel info output_base)/external
-```
-
-Note that running `bazel clean` will not actually delete the external
-directory. To remove all external artifacts, use `bazel clean --expunge`.
-
-## Offline builds {:#offline-builds}
-
-It is sometimes desirable or necessary to run a build in an offline fashion. For
-simple use cases, such as traveling on an airplane,
-[prefetching](#fetching-dependencies) the needed
-repositories with `bazel fetch` or `bazel sync` can be enough; moreover, the
-using the option `--nofetch`, fetching of further repositories can be disabled
-during the build.
-
-For true offline builds, where the providing of the needed files is to be done
-by an entity different from bazel, bazel supports the option
-`--distdir`. Whenever a repository rule asks bazel to fetch a file via
-[`ctx.download`](/rules/lib/repository_ctx#download) or
-[`ctx.download_and_extract`](/rules/lib/repository_ctx#download_and_extract)
-and provides a hash sum of the file
-needed, bazel will first look into the directories specified by that option for
-a file matching the basename of the first URL provided, and use that local copy
-if the hash matches.
-
-Bazel itself uses this technique to bootstrap offline from the [distribution
-artifact](https://github.com/bazelbuild/bazel-website/blob/master/designs/_posts/2016-10-11-distribution-artifact.md).
-It does so by [collecting all the needed external
-dependencies](https://github.com/bazelbuild/bazel/blob/5cfa0303d6ac3b5bd031ff60272ce80a704af8c2/WORKSPACE#L116){: .external}
-in an internal
-[`distdir_tar`](https://github.com/bazelbuild/bazel/blob/5cfa0303d6ac3b5bd031ff60272ce80a704af8c2/distdir.bzl#L44){: .external}.
-
-However, bazel allows the execution of arbitrary commands in repository rules,
-without knowing if they call out to the network. Therefore, bazel has no option
-to enforce builds being fully offline. So testing if a build works correctly
-offline requires external blocking of the network, as bazel does in its
-bootstrap test.
-
-## Best practices {:#best-practices}
-
-### Repository rules {:#repository-rules}
-
-A repository rule should generally be responsible for:
-
--  Detecting system settings and writing them to files.
--  Finding resources elsewhere on the system.
--  Downloading resources from URLs.
--  Generating or symlinking BUILD files into the external repository directory.
-
-Avoid using `repository_ctx.execute` when possible. For example, when using a non-Bazel C++
-library that has a build using Make, it is preferable to use `repository_ctx.download()` and then
-write a BUILD file that builds it, instead of running `ctx.execute(["make"])`.
-
-Prefer [`http_archive`](/rules/lib/repo/http#http_archive) to `git_repository`.
-The reasons are:
-
-* Git repository rules depend on system `git(1)` whereas the HTTP downloader is built
-  into Bazel and has no system dependencies.
-* `http_archive` supports a list of `urls` as mirrors, and `git_repository` supports only
-  a single `remote`.
-* `http_archive` works with the [repository cache](/run/build#repository-cache), but not
-  `git_repository`. See
-   [#5116](https://github.com/bazelbuild/bazel/issues/5116){: .external} for more information.
-
-Do not use `bind()`. See "[Consider removing
-bind](https://github.com/bazelbuild/bazel/issues/1952){: .external}" for a long
-discussion of its issues and alternatives.
diff --git a/site/en/concepts/build-ref.md b/site/en/concepts/build-ref.md
index 282037c..0849177 100644
--- a/site/en/concepts/build-ref.md
+++ b/site/en/concepts/build-ref.md
@@ -5,58 +5,59 @@
 
 {% include "_buttons.html" %}
 
-Bazel builds software from source code organized in a directory tree called
-a workspace. Source files in the workspace are organized in a nested
-hierarchy of packages, where each package is a directory that contains a set
-of related source files and one `BUILD` file. The `BUILD` file specifies what
-software outputs can be built from the source.
+Bazel builds software from source code organized in a directory tree called a
+workspace. Source files in the workspace are organized in a nested hierarchy of
+packages, where each package is a directory that contains a set of related
+source files and one `BUILD` file. The `BUILD` file specifies what software
+outputs can be built from the source.
 
 ## Workspace {:#workspace}
 
 A _workspace_ is a directory tree on your filesystem that contains the source
 files for the software you want to build. Each workspace has a text file named
-`WORKSPACE` which may be empty, or may contain references to
-[external dependencies](/docs/external) required to build the outputs.
+`WORKSPACE` which may be empty, or may contain references to [external
+dependencies](/docs/external) required to build the outputs.
 
 Directories containing a file called `WORKSPACE` are considered the root of a
-workspace. Therefore, Bazel ignores any directory trees in a workspace rooted
-at a subdirectory containing a `WORKSPACE` file, as they form another workspace.
+workspace. Therefore, Bazel ignores any directory trees in a workspace rooted at
+a subdirectory containing a `WORKSPACE` file, as they form another workspace.
 
-Bazel also supports `WORKSPACE.bazel` file as an alias of `WORKSPACE` file.
-If both files exist, `WORKSPACE.bazel` is used.
+Bazel also supports `WORKSPACE.bazel` file as an alias of `WORKSPACE` file. If
+both files exist, `WORKSPACE.bazel` is used.
 
 ### Repositories {:#repositories}
 
 Code is organized in _repositories_. The directory containing the `WORKSPACE`
 file is the root of the main repository, also called `@`. Other, (external)
-repositories are defined in the `WORKSPACE` file using workspace rules.
+repositories are defined in the `WORKSPACE` file using workspace rules, or
+generated from modules and extensions in the Bzlmod system. See [external
+dependencies overview](/external/overview) for more information.
 
-The workspace rules bundled with Bazel are documented in the
-[Workspace Rules](/reference/be/workspace) section in the
-[Build Encyclopedia](/reference/be/overview) and the documentation on
-[embedded Starlark repository rules](/rules/lib/repo/index).
+The workspace rules bundled with Bazel are documented in the [Workspace
+Rules](/reference/be/workspace) section in the [Build
+Encyclopedia](/reference/be/overview) and the documentation on [embedded
+Starlark repository rules](/rules/lib/repo/index).
 
 As external repositories are repositories themselves, they often contain a
 `WORKSPACE` file as well. However, these additional `WORKSPACE` files are
-ignored by Bazel. In particular, repositories depended upon transitively are
-not added automatically.
+ignored by Bazel. In particular, repositories depended upon transitively are not
+added automatically.
 
 ## Packages {:#packages}
 
 The primary unit of code organization in a repository is the _package_. A
-package is a collection of related files and a specification of how they
-can be used to produce output artifacts.
+package is a collection of related files and a specification of how they can be
+used to produce output artifacts.
 
-A package is defined as a directory containing a file named `BUILD`
-(or `BUILD.bazel`).  A package includes all files in its directory, plus
-all subdirectories beneath it, except those which themselves contain a
-`BUILD` file. From this definition, no file or directory may be a part of
-two different packages.
+A package is defined as a directory containing a file named `BUILD` (or
+`BUILD.bazel`). A package includes all files in its directory, plus all
+subdirectories beneath it, except those which themselves contain a `BUILD` file.
+From this definition, no file or directory may be a part of two different
+packages.
 
-For example, in the following directory tree
-there are two packages, `my/app`, and the subpackage `my/app/tests`.
-Note that `my/app/data` is not a package, but a directory
-belonging to package `my/app`.
+For example, in the following directory tree there are two packages, `my/app`,
+and the subpackage `my/app/tests`. Note that `my/app/data` is not a package, but
+a directory belonging to package `my/app`.
 
 ```
 src/my/app/BUILD
@@ -69,52 +70,47 @@
 ## Targets {:#targets}
 
 A package is a container of _targets_, which are defined in the package's
-`BUILD` file.  Most targets are one of two principal kinds, _files_ and _rules_.
+`BUILD` file. Most targets are one of two principal kinds, _files_ and _rules_.
 
-Files are further divided into two kinds.  _Source files_ are usually
-written by the efforts of people, and checked in to the repository.
-_Generated files_, sometimes called derived files or output files,
-are not checked in, but are generated from source files.
+Files are further divided into two kinds. _Source files_ are usually written by
+the efforts of people, and checked in to the repository. _Generated files_,
+sometimes called derived files or output files, are not checked in, but are
+generated from source files.
 
-The second kind of target is declared with a _rule_.  Each rule
-instance specifies the relationship between a set of input and a set of
-output files.  The inputs to a rule may be source files, but they also
-may be the outputs of other rules.
+The second kind of target is declared with a _rule_. Each rule instance
+specifies the relationship between a set of input and a set of output files. The
+inputs to a rule may be source files, but they also may be the outputs of other
+rules.
 
-Whether the input to a rule is a source file or a generated file is
-in most cases immaterial; what matters is only the contents of that
-file. This fact makes it easy to replace a complex source file with
-a generated file produced by a rule, such as happens when the burden
-of manually maintaining a highly structured file becomes too
-tiresome, and someone writes a program to derive it. No change is
-required to the consumers of that file. Conversely, a generated
-file may easily be replaced by a source file with only local
-changes.
+Whether the input to a rule is a source file or a generated file is in most
+cases immaterial; what matters is only the contents of that file. This fact
+makes it easy to replace a complex source file with a generated file produced by
+a rule, such as happens when the burden of manually maintaining a highly
+structured file becomes too tiresome, and someone writes a program to derive it.
+No change is required to the consumers of that file. Conversely, a generated
+file may easily be replaced by a source file with only local changes.
 
-The inputs to a rule may also include _other rules_. The
-precise meaning of such relationships is often quite complex and
-language- or rule-dependent, but intuitively it is simple: a C++
-library rule A might have another C++ library rule B for an input.
-The effect of this dependency is that B's header files are
-available to A during compilation, B's symbols are available to A
-during linking, and B's runtime data is available to A during
-execution.
+The inputs to a rule may also include _other rules_. The precise meaning of such
+relationships is often quite complex and language- or rule-dependent, but
+intuitively it is simple: a C++ library rule A might have another C++ library
+rule B for an input. The effect of this dependency is that B's header files are
+available to A during compilation, B's symbols are available to A during
+linking, and B's runtime data is available to A during execution.
 
-An invariant of all rules is that the files generated by a rule
-always belong to the same package as the rule itself; it is not
-possible to generate files into another package. It is not uncommon
-for a rule's inputs to come from another package, though.
+An invariant of all rules is that the files generated by a rule always belong to
+the same package as the rule itself; it is not possible to generate files into
+another package. It is not uncommon for a rule's inputs to come from another
+package, though.
 
-Package groups are sets of packages whose purpose is to limit accessibility
-of certain rules. Package groups are defined by the `package_group` function.
-They have three properties: the list of packages they contain, their name, and
-other package groups they include. The only allowed ways to refer to them are
-from the `visibility` attribute of rules or from the `default_visibility`
-attribute of the `package` function; they do not generate or consume files.
-For more information, refer to the
-[`package_group` documentation](/reference/be/functions#package_group).
-
+Package groups are sets of packages whose purpose is to limit accessibility of
+certain rules. Package groups are defined by the `package_group` function. They
+have three properties: the list of packages they contain, their name, and other
+package groups they include. The only allowed ways to refer to them are from the
+`visibility` attribute of rules or from the `default_visibility` attribute of
+the `package` function; they do not generate or consume files. For more
+information, refer to the [`package_group`
+documentation](/reference/be/functions#package_group).
 
 <a class="button button-with-icon button-primary" href="/concepts/labels">
   Labels<span class="material-icons icon-after" aria-hidden="true">arrow_forward</span>
-</a>
+</a>
\ No newline at end of file
diff --git a/site/en/docs/external.md b/site/en/docs/external.md
deleted file mode 100644
index b69723c..0000000
--- a/site/en/docs/external.md
+++ /dev/null
@@ -1,371 +0,0 @@
-Project: /_project.yaml
-Book: /_book.yaml
-
-# Working with External Dependencies
-
-{% include "_buttons.html" %}
-
-Bazel can depend on targets from other projects. Dependencies from these other
-projects are called _external dependencies_.
-
-Note: Bazel 5.0 and newer has a new external dependency system, codenamed
-"Bzlmod", which renders a lot of the content on this page obsolete. See [Bzlmod
-user guide](/build/bzlmod) for more information.
-
-The `WORKSPACE` file (or `WORKSPACE.bazel` file) in the
-[workspace directory](/concepts/build-ref#workspace)
-tells Bazel how to get other projects' sources. These other projects can
-contain one or more `BUILD` files with their own targets. `BUILD` files within
-the main project can depend on these external targets by using their name from
-the `WORKSPACE` file.
-
-For example, suppose there are two projects on a system:
-
-```
-/
-  home/
-    user/
-      project1/
-        WORKSPACE
-        BUILD
-        srcs/
-          ...
-      project2/
-        WORKSPACE
-        BUILD
-        my-libs/
-```
-
-If `project1` wanted to depend on a target, `:foo`, defined in
-`/home/user/project2/BUILD`, it could specify that a repository named
-`project2` could be found at `/home/user/project2`. Then targets in
-`/home/user/project1/BUILD` could depend on `@project2//:foo`.
-
-The `WORKSPACE` file allows users to depend on targets from other parts of the
-filesystem or downloaded from the internet. It uses the same syntax as `BUILD`
-files, but allows a different set of rules called _repository rules_ (sometimes
-also known as _workspace rules_). Bazel comes with a few
-[built-in repository rules](/reference/be/workspace) and a set of
-[embedded Starlark repository rules](/rules/lib/repo/index).
-Users can also write [custom repository rules](/extending/repo)
-to get more complex behavior.
-
-## Supported types of external dependencies {:#types}
-
-A few basic types of external dependencies can be used:
-
-- [Dependencies on other Bazel projects](#bazel-projects)
-- [Dependencies on non-Bazel projects](#non-bazel-projects)
-- [Dependencies on external packages](#external-packages)
-
-### Depending on other Bazel projects {:#bazel-projects}
-
-If you want to use targets from a second Bazel project, you can
-use
-[`local_repository`](/reference/be/workspace#local_repository),
-[`git_repository`](/rules/lib/repo/git#git_repository)
-or [`http_archive`](/rules/lib/repo/http#http_archive)
-to symlink it from the local filesystem, reference a git repository or download
-it (respectively).
-
-For example, suppose you are working on a project, `my-project/`, and you want
-to depend on targets from your coworker's project, `coworkers-project/`. Both
-projects use Bazel, so you can add your coworker's project as an external
-dependency and then use any targets your coworker has defined from your own
-BUILD files. You would add the following to `my_project/WORKSPACE`:
-
-```python
-local_repository(
-    name = "coworkers_project",
-    path = "/path/to/coworkers-project",
-)
-```
-
-If your coworker has a target `//foo:bar`, your project can refer to it as
-`@coworkers_project//foo:bar`. External project names must be
-[valid workspace names](/rules/lib/globals#workspace).
-
-### Depending on non-Bazel projects {:#non-bazel-projects}
-
-Rules prefixed with `new_`, such as
-[`new_local_repository`](/reference/be/workspace#new_local_repository),
-allow you to create targets from projects that do not use Bazel.
-
-For example, suppose you are working on a project, `my-project/`, and you want
-to depend on your coworker's project, `coworkers-project/`. Your coworker's
-project uses `make` to build, but you'd like to depend on one of the .so files
-it generates. To do so, add the following to `my_project/WORKSPACE`:
-
-```python
-new_local_repository(
-    name = "coworkers_project",
-    path = "/path/to/coworkers-project",
-    build_file = "coworker.BUILD",
-)
-```
-
-`build_file` specifies a `BUILD` file to overlay on the existing project, for
-example:
-
-```python
-cc_library(
-    name = "some-lib",
-    srcs = glob(["**"]),
-    visibility = ["//visibility:public"],
-)
-```
-
-You can then depend on `@coworkers_project//:some-lib` from your project's
-`BUILD` files.
-
-### Depending on external packages {:#external-packages}
-
-#### Maven artifacts and repositories {:#maven-repositories}
-
-Use the ruleset [`rules_jvm_external`](https://github.com/bazelbuild/rules_jvm_external){: .external}
-to download artifacts from Maven repositories and make them available as Java
-dependencies.
-
-## Fetching dependencies {:#fetching-dependencies}
-
-By default, external dependencies are fetched as needed during `bazel build`. If
-you would like to prefetch the dependencies needed for a specific set of targets, use
-[`bazel fetch`](/reference/command-line-reference#commands).
-To unconditionally fetch all external dependencies, use
-[`bazel sync`](/reference/command-line-reference#commands).
-As fetched repositories are [stored in the output base](#layout), fetching
-happens per workspace.
-
-## Shadowing dependencies {:#shadowing-dependencies}
-
-Whenever possible, it is recommended to have a single version policy in your
-project. This is required for dependencies that you compile against and end up
-in your final binary. But for cases where this isn't true, it is possible to
-shadow dependencies. Consider the following scenario:
-
-myproject/WORKSPACE
-
-```python
-workspace(name = "myproject")
-
-local_repository(
-    name = "A",
-    path = "../A",
-)
-local_repository(
-    name = "B",
-    path = "../B",
-)
-```
-
-A/WORKSPACE
-
-```python
-workspace(name = "A")
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-http_archive(
-    name = "testrunner",
-    urls = ["https://github.com/testrunner/v1.zip"],
-    sha256 = "...",
-)
-```
-
-B/WORKSPACE
-
-```python
-workspace(name = "B")
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-http_archive(
-    name = "testrunner",
-    urls = ["https://github.com/testrunner/v2.zip"],
-    sha256 = "..."
-)
-```
-
-Both dependencies `A` and `B` depend on `testrunner`, but they depend on
-different versions of `testrunner`. There is no reason for these test runners to
-not peacefully coexist within `myproject`, however they will clash with each
-other since they have the same name. To declare both dependencies,
-update myproject/WORKSPACE:
-
-```python
-workspace(name = "myproject")
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-http_archive(
-    name = "testrunner-v1",
-    urls = ["https://github.com/testrunner/v1.zip"],
-    sha256 = "..."
-)
-http_archive(
-    name = "testrunner-v2",
-    urls = ["https://github.com/testrunner/v2.zip"],
-    sha256 = "..."
-)
-local_repository(
-    name = "A",
-    path = "../A",
-    repo_mapping = {"@testrunner" : "@testrunner-v1"}
-)
-local_repository(
-    name = "B",
-    path = "../B",
-    repo_mapping = {"@testrunner" : "@testrunner-v2"}
-)
-```
-
-This mechanism can also be used to join diamonds. For example if `A` and `B`
-had the same dependency but call it by different names, those dependencies can
-be joined in myproject/WORKSPACE.
-
-## Overriding repositories from the command line {:#overriding-repositories}
-
-To override a declared repository with a local repository from the command line,
-use the
-[`--override_repository`](/reference/command-line-reference#flag--override_repository)
-flag. Using this flag changes the contents of external repositories without
-changing your source code.
-
-For example, to override `@foo` to the local directory `/path/to/local/foo`,
-pass the `--override_repository=foo=/path/to/local/foo` flag.
-
-Some of the use cases include:
-
-* Debugging issues. For example, you can override a `http_archive` repository
-  to a local directory where you can make changes more easily.
-* Vendoring. If you are in an environment where you cannot make network calls,
-  override the network-based repository rules to point to local directories
-  instead.
-
-## Using proxies {:#using-proxies}
-
-Bazel will pick up proxy addresses from the `HTTPS_PROXY` and `HTTP_PROXY`
-environment variables and use these to download HTTP/HTTPS files (if specified).
-
-## Support for IPv6 {:#support-for-ipv6}
-
-On IPv6-only machines, Bazel will be able to download dependencies with
-no changes. On dual-stack IPv4/IPv6 machines, however, Bazel follows the same
-convention as Java: if IPv4 is enabled, IPv4 is preferred. In some situations,
-for example when IPv4 network is unable to resolve/reach external addresses,
-this can cause `Network unreachable` exceptions and build failures.
-In these cases, you can override Bazel's behavior to prefer IPv6
-by using [`java.net.preferIPv6Addresses=true` system property](https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html){: .external}.
-Specifically:
-
-* Use `--host_jvm_args=-Djava.net.preferIPv6Addresses=true`
-  [startup option](/docs/user-manual#startup-options),
-  for example by adding the following line in your
-  [`.bazelrc` file](/run/bazelrc):
-
-  `startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true`
-
-* If you are running Java build targets that need to connect to the internet
-  as well (integration tests sometimes needs that), also use
-  `--jvmopt=-Djava.net.preferIPv6Addresses=true`
-  [tool flag](/docs/user-manual#jvmopt), for example by having the
-  following line in your [`.bazelrc` file](/run/bazelrc):
-
-  `build --jvmopt=-Djava.net.preferIPv6Addresses`
-
-* If you are using
-  [rules_jvm_external](https://github.com/bazelbuild/rules_jvm_external){: .external},
-  for example, for dependency version resolution, also add
-  `-Djava.net.preferIPv6Addresses=true` to the `COURSIER_OPTS`
-  environment variable to [provide JVM options for Coursier](https://github.com/bazelbuild/rules_jvm_external#provide-jvm-options-for-coursier-with-coursier_opts){: .external}
-
-## Transitive dependencies {:#transitive-dependencies}
-
-Bazel only reads dependencies listed in your `WORKSPACE` file. If your project
-(`A`) depends on another project (`B`) which lists a dependency on a third
-project (`C`) in its `WORKSPACE` file, you'll have to add both `B`
-and `C` to your project's `WORKSPACE` file. This requirement can balloon the
-`WORKSPACE` file size, but limits the chances of having one library
-include `C` at version 1.0 and another include `C` at 2.0.
-
-## Caching of external dependencies {:#caching-external-dependencies}
-
-By default, Bazel will only re-download external dependencies if their
-definition changes. Changes to files referenced in the definition (such as patches
-or `BUILD` files) are also taken into account by bazel.
-
-To force a re-download, use `bazel sync`.
-
-## Layout {:#layout}
-
-External dependencies are all downloaded to a directory under the subdirectory
-`external` in the [output base](/remote/output-directories). In case of a
-[local repository](/reference/be/workspace#local_repository), a symlink is created
-there instead of creating a new directory.
-You can see the `external` directory by running:
-
-```posix-terminal
-ls $(bazel info output_base)/external
-```
-
-Note that running `bazel clean` will not actually delete the external
-directory. To remove all external artifacts, use `bazel clean --expunge`.
-
-## Offline builds {:#offline-builds}
-
-It is sometimes desirable or necessary to run a build in an offline fashion. For
-simple use cases, such as traveling on an airplane,
-[prefetching](#fetching-dependencies) the needed
-repositories with `bazel fetch` or `bazel sync` can be enough; moreover, the
-using the option `--nofetch`, fetching of further repositories can be disabled
-during the build.
-
-For true offline builds, where the providing of the needed files is to be done
-by an entity different from bazel, bazel supports the option
-`--distdir`. Whenever a repository rule asks bazel to fetch a file via
-[`ctx.download`](/rules/lib/repository_ctx#download) or
-[`ctx.download_and_extract`](/rules/lib/repository_ctx#download_and_extract)
-and provides a hash sum of the file
-needed, bazel will first look into the directories specified by that option for
-a file matching the basename of the first URL provided, and use that local copy
-if the hash matches.
-
-Bazel itself uses this technique to bootstrap offline from the [distribution
-artifact](https://github.com/bazelbuild/bazel-website/blob/master/designs/_posts/2016-10-11-distribution-artifact.md).
-It does so by [collecting all the needed external
-dependencies](https://github.com/bazelbuild/bazel/blob/5cfa0303d6ac3b5bd031ff60272ce80a704af8c2/WORKSPACE#L116){: .external}
-in an internal
-[`distdir_tar`](https://github.com/bazelbuild/bazel/blob/5cfa0303d6ac3b5bd031ff60272ce80a704af8c2/distdir.bzl#L44){: .external}.
-
-However, bazel allows the execution of arbitrary commands in repository rules,
-without knowing if they call out to the network. Therefore, bazel has no option
-to enforce builds being fully offline. So testing if a build works correctly
-offline requires external blocking of the network, as bazel does in its
-bootstrap test.
-
-## Best practices {:#best-practices}
-
-### Repository rules {:#repository-rules}
-
-A repository rule should generally be responsible for:
-
--  Detecting system settings and writing them to files.
--  Finding resources elsewhere on the system.
--  Downloading resources from URLs.
--  Generating or symlinking BUILD files into the external repository directory.
-
-Avoid using `repository_ctx.execute` when possible. For example, when using a non-Bazel C++
-library that has a build using Make, it is preferable to use `repository_ctx.download()` and then
-write a BUILD file that builds it, instead of running `ctx.execute(["make"])`.
-
-Prefer [`http_archive`](/rules/lib/repo/http#http_archive) to `git_repository`.
-The reasons are:
-
-* Git repository rules depend on system `git(1)` whereas the HTTP downloader is built
-  into Bazel and has no system dependencies.
-* `http_archive` supports a list of `urls` as mirrors, and `git_repository` supports only
-  a single `remote`.
-* `http_archive` works with the [repository cache](/run/build#repository-cache), but not
-  `git_repository`. See
-   [#5116](https://github.com/bazelbuild/bazel/issues/5116){: .external} for more information.
-
-Do not use `bind()`. See "[Consider removing
-bind](https://github.com/bazelbuild/bazel/issues/1952){: .external}" for a long
-discussion of its issues and alternatives.
diff --git a/site/en/external/advanced.md b/site/en/external/advanced.md
new file mode 100644
index 0000000..6e4f472
--- /dev/null
+++ b/site/en/external/advanced.md
@@ -0,0 +1,184 @@
+Project: /_project.yaml
+Book: /_book.yaml
+
+# Advanced topics on external dependencies
+
+{% include "_buttons.html" %}
+
+## Shadowing dependencies in WORKSPACE
+
+Note: This section applies to the [WORKSPACE
+system](/external/overview#workspace-system) only. For
+[Bzlmod](/external/overview#bzlmod), use a [multiple-version
+override](/external/module#multiple-version_override).
+
+Whenever possible, have a single version policy in your project, which is
+required for dependencies that you compile against and end up in your final
+binary. For other cases, you can shadow dependencies:
+
+myproject/WORKSPACE
+
+```python
+workspace(name = "myproject")
+
+local_repository(
+    name = "A",
+    path = "../A",
+)
+local_repository(
+    name = "B",
+    path = "../B",
+)
+```
+
+A/WORKSPACE
+
+```python
+workspace(name = "A")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+http_archive(
+    name = "testrunner",
+    urls = ["https://github.com/testrunner/v1.zip"],
+    sha256 = "...",
+)
+```
+
+B/WORKSPACE {# This is not a buganizer link okay?? #}
+
+```python
+workspace(name = "B")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+http_archive(
+    name = "testrunner",
+    urls = ["https://github.com/testrunner/v2.zip"],
+    sha256 = "..."
+)
+```
+
+Both dependencies `A` and `B` depend on different versions of `testrunner`.
+Include both in `myproject` without conflict by giving them distinct names in
+`myproject/WORKSPACE`:
+
+```python
+workspace(name = "myproject")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+http_archive(
+    name = "testrunner-v1",
+    urls = ["https://github.com/testrunner/v1.zip"],
+    sha256 = "..."
+)
+http_archive(
+    name = "testrunner-v2",
+    urls = ["https://github.com/testrunner/v2.zip"],
+    sha256 = "..."
+)
+local_repository(
+    name = "A",
+    path = "../A",
+    repo_mapping = {"@testrunner" : "@testrunner-v1"}
+)
+local_repository(
+    name = "B",
+    path = "../B",
+    repo_mapping = {"@testrunner" : "@testrunner-v2"}
+)
+```
+
+You can also use this mechanism to join diamonds. For example, if `A` and `B`
+have the same dependency but call it by different names, join those dependencies
+in `myproject/WORKSPACE`.
+
+## Overriding repositories from the command line {:#overriding-repositories}
+
+To override a declared repository with a local repository from the command line,
+use the
+[`--override_repository`](/reference/command-line-reference#flag--override_repository)
+flag. Using this flag changes the contents of external repositories without
+changing your source code.
+
+For example, to override `@foo` to the local directory `/path/to/local/foo`,
+pass the `--override_repository=foo=/path/to/local/foo` flag.
+
+Use cases include:
+
+*   Debugging issues. For example, to override an `http_archive` repository to a
+    local directory where you can make changes more easily.
+*   Vendoring. If you are in an environment where you cannot make network calls,
+    override the network-based repository rules to point to local directories
+    instead.
+
+Note: With [Bzlmod](/external/overview#bzlmod), remember to use canonical repo
+names here. Alternatively, use the
+[`--override_module`](/reference/command-line-reference#flag--override_module)
+flag to override a module to a local directory, similar to the
+[`local_path_override`](/rules/lib/globals#local_path_override) directive in
+`MODULE.bazel`.
+
+## Using proxies
+
+Bazel picks up proxy addresses from the `HTTPS_PROXY` and `HTTP_PROXY`
+environment variables and uses these to download `HTTP` and `HTTPS` files (if
+specified).
+
+## Support for IPv6
+
+On IPv6-only machines, Bazel can download dependencies with no changes. However,
+on dual-stack IPv4/IPv6 machines Bazel follows the same convention as Java,
+preferring IPv4 if enabled. In some situations, for example when the IPv4
+network cannot resolve/reach external addresses, this can cause `Network
+unreachable` exceptions and build failures. In these cases, you can override
+Bazel's behavior to prefer IPv6 by using the
+[`java.net.preferIPv6Addresses=true` system
+property](https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html){: .external}.
+Specifically:
+
+*   Use `--host_jvm_args=-Djava.net.preferIPv6Addresses=true` [startup
+    option](/docs/user-manual#startup-options), for example by adding the
+    following line in your [`.bazelrc` file](/run/bazelrc):
+
+    `startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true`
+
+*   When running Java build targets that need to connect to the internet (such
+    as for integration tests), use the
+    `--jvmopt=-Djava.net.preferIPv6Addresses=true` [tool
+    flag](/docs/user-manual#jvmopt). For example, include in your [`.bazelrc`
+    file](/run/bazelrc):
+
+    `build --jvmopt=-Djava.net.preferIPv6Addresses`
+
+*   If you are using [`rules_jvm_external`](https://github.com/bazelbuild/rules_jvm_external){: .external}
+    for dependency version resolution, also add
+    `-Djava.net.preferIPv6Addresses=true` to the `COURSIER_OPTS` environment
+    variable to [provide JVM options for
+    Coursier](https://github.com/bazelbuild/rules_jvm_external#provide-jvm-options-for-coursier-with-coursier_opts){: .external}.
+
+## Offline builds
+
+Sometimes you may wish to run a build offline, such as when traveling on an
+airplane. For such simple use cases, prefetch the needed repositories with
+`bazel fetch` or `bazel sync`. To disable fetching further repositories during
+the build, use the option `--nofetch`.
+
+For true offline builds, where a different entity supplies all needed files,
+Bazel supports the option `--distdir`. This flag tells Bazel to look first into
+the directories specified by that option when a repository rule asks Bazel to
+fetch a file with [`ctx.download`](/rules/lib/repository_ctx#download) or
+[`ctx.download_and_extract`](/rules/lib/repository_ctx#download_and_extract). By
+providing a hash sum of the file needed, Bazel looks for a file matching the
+basename of the first URL, and uses the local copy if the hash matches.
+
+Bazel itself uses this technique to bootstrap offline from the [distribution
+artifact](https://github.com/bazelbuild/bazel-website/blob/master/designs/_posts/2016-10-11-distribution-artifact.md).
+It does so by [collecting all the needed external
+dependencies](https://github.com/bazelbuild/bazel/blob/5cfa0303d6ac3b5bd031ff60272ce80a704af8c2/WORKSPACE#L116){: .external}
+in an internal
+[`distdir_tar`](https://github.com/bazelbuild/bazel/blob/5cfa0303d6ac3b5bd031ff60272ce80a704af8c2/distdir.bzl#L44){: .external}.
+
+Bazel allows execution of arbitrary commands in repository rules without knowing
+if they call out to the network, and so cannot enforce fully offline builds. To
+test if a build works correctly offline, manually block off the network (as
+Bazel does in its [bootstrap
+test](https://cs.opensource.google/bazel/bazel/+/master:src/test/shell/bazel/BUILD;l=1073;drc=88c426e73cc0eb0a41c0d7995e36acd94e7c9a48){: .external}).
\ No newline at end of file
diff --git a/site/en/external/extension.md b/site/en/external/extension.md
new file mode 100644
index 0000000..26dd228
--- /dev/null
+++ b/site/en/external/extension.md
@@ -0,0 +1,144 @@
+Project: /_project.yaml
+Book: /_book.yaml
+
+# Module extensions
+
+{% include "_buttons.html" %}
+
+Module extensions allow users to extend the module system by reading input data
+from modules across the dependency graph, performing necessary logic to resolve
+dependencies, and finally creating repos by calling repo rules. These extensions
+have capabilities similar to repo rules, which enables them to perform file I/O,
+send network requests, and so on. Among other things, they allow Bazel to
+interact with other package management systems while also respecting the
+dependency graph built out of Bazel modules.
+
+You can define module extensions in `.bzl` files, just like repo rules. They're
+not invoked directly; rather, each module specifies pieces of data called *tags*
+for extensions to read. Bazel runs module resolution before evaluating any
+extensions. The extension reads all the tags belonging to it across the entire
+dependency graph.
+
+## Extension usage
+
+Extensions are hosted in Bazel modules themselves. To use an extension in a
+module, first add a `bazel_dep` on the module hosting the extension, and then
+call the [`use_extension`](/rules/lib/globals#use_extension) built-in function
+to bring it into scope. Consider the following example — a snippet from a
+`MODULE.bazel` file to use the "maven" extension defined in the
+[`rules_jvm_external`](https://github.com/bazelbuild/rules_jvm_external){:.external}
+module:
+
+```python
+bazel_dep(name = "rules_jvm_external", version = "4.5")
+maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
+```
+
+This binds the return value of `use_extension` to a variable, which allows the
+user to use dot-syntax to specify tags for the extension. The tags must follow
+the schema defined by the corresponding *tag classes* specified in the
+[extension definition](#extension_definition). For an example specifying some
+`maven.install` and `maven.artifact` tags:
+
+```python
+maven.install(artifacts = ["org.junit:junit:4.13.2"])
+maven.artifact(group = "com.google.guava",
+               artifact = "guava",
+               version = "27.0-jre",
+               exclusions = ["com.google.j2objc:j2objc-annotations"])
+```
+
+Use the [`use_repo`](/rules/lib/globals#use_repo) directive to bring repos
+generated by the extension into the scope of the current module.
+
+```python
+use_repo(maven, "maven")
+```
+
+Repos generated by an extension are part of its API. In this example, the
+"maven" module extension promises to generate a repo called `maven`. With the
+declaration above, the extension properly resolves labels such as
+`@maven//:org_junit_junit` to point to the repo generated by the "maven"
+extension.
+
+## Extension definition
+
+You can define module extensions similarly to repo rules, using the
+[`module_extension`](/rules/lib/globals#module_extension) function. However,
+while repo rules have a number of attributes, module extensions have
+[`tag_class`es](/rules/lib/globals#tag_class), each of which has a number of
+attributes. The tag classes define schemas for tags used by this extension. For
+example, the "maven" extension above might be defined like this:
+
+```python
+# @rules_jvm_external//:extensions.bzl
+
+_install = tag_class(attrs = {"artifacts": attr.string_list(), ...})
+_artifact = tag_class(attrs = {"group": attr.string(), "artifact": attr.string(), ...})
+maven = module_extension(
+  implementation = _maven_impl,
+  tag_classes = {"install": _install, "artifact": _artifact},
+)
+```
+
+These declarations show that `maven.install` and `maven.artifact` tags can be
+specified using the specified attribute schema.
+
+The implementation function of module extensions are similar to those of repo
+rules, except that they get a [`module_ctx`](/rules/lib/module_ctx) object,
+which grants access to all modules using the extension and all pertinent tags.
+The implementation function then calls repo rules to generate repos.
+
+```python
+# @rules_jvm_external//:extensions.bzl
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")  # a repo rule
+def _maven_impl(ctx):
+  # This is a fake implementation for demonstration purposes only
+
+  # collect artifacts from across the dependency graph
+  artifacts = []
+  for mod in ctx.modules:
+    for install in mod.tags.install:
+      artifacts += install.artifacts
+    artifacts += [_to_artifact(artifact) for artifact in mod.tags.artifact]
+
+  # call out to the coursier CLI tool to resolve dependencies
+  output = ctx.execute(["coursier", "resolve", artifacts])
+  repo_attrs = _process_coursier_output(output)
+
+  # call repo rules to generate repos
+  for attrs in repo_attrs:
+    http_file(**attrs)
+  _generate_hub_repo(name = "maven", repo_attrs)
+```
+
+## Repository names and visibility
+
+Repos generated by extensions have canonical names in the form of `{{ "<var>"
+}}module_repo_canonical_name{{ "</var>" }}~{{ "<var>" }}extension_name{{
+"</var>" }}~{{ "<var>" }}repo_name{{ "</var>" }}`. For extensions hosted in the
+root module, the `{{ "<var>" }}module_repo_canonical_name{{ "</var>" }}` part is
+replaced with the string `_main`. Note that the canonical name format is not an
+API you should depend on — it's subject to change at any time.
+
+This naming policy means that each extension has its own "repo namespace"; two
+distinct extensions can each define a repo with the same name without risking
+any clashes. It also means that `repository_ctx.name` reports the canonical name
+of the repo, which is *not* the same as the name specified in the repo rule
+call.
+
+Taking repos generated by module extensions into consideration, there are
+several repo visibility rules:
+
+*   A Bazel module repo can see all repos introduced in its `MODULE.bazel` file
+    via [`bazel_dep`](/rules/lib/globals#bazel_dep) and
+    [`use_repo`](/rules/lib/globals#use_repo).
+*   A repo generated by a module extension can see all repos visible to the
+    module that hosts the extension, *plus* all other repos generated by the
+    same module extension (using the names specified in the repo rule calls as
+    their apparent names).
+    *   This might result in a conflict. If the module repo can see a repo with
+        the apparent name `foo`, and the extension generates a repo with the
+        specified name `foo`, then for all repos generated by that extension
+        `foo` refers to the former.
\ No newline at end of file
diff --git a/site/en/external/module.md b/site/en/external/module.md
new file mode 100644
index 0000000..f660f2f
--- /dev/null
+++ b/site/en/external/module.md
@@ -0,0 +1,193 @@
+Project: /_project.yaml
+Book: /_book.yaml
+
+# Bazel modules
+
+{% include "_buttons.html" %}
+
+A Bazel **module** is a Bazel project that can have multiple versions, each of
+which publishes metadata about other modules that it depends on. This is
+analogous to familiar concepts in other dependency management systems, such as a
+Maven *artifact*, an npm *package*, a Go *module*, or a Cargo *crate*.
+
+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 direct dependencies, and other information. For 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")
+```
+
+<!-- TODO(wyv): add link to MODULE.bazel globals -->
+
+To perform module resolution, Bazel starts by reading the root module's
+`MODULE.bazel` file, and then repeatedly requests any dependency's
+`MODULE.bazel` file from a [Bazel registry](/external/registry) until it
+discovers the entire dependency graph.
+
+By default, Bazel then [selects](#version_selection) one version of each module
+to use. Bazel represents each module with a repo, and consults the registry
+again to learn how to define each of the repos.
+
+## Version format
+
+Bazel has a diverse ecosystem and projects use various versioning schemes. The
+most popular by far is [SemVer](https://semver.org){: .external}, but there are
+also prominent projects using different schemes such as
+[Abseil](https://github.com/abseil/abseil-cpp/releases){: .external}, whose
+versions are date-based, for example `20210324.2`).
+
+For this reason, Bzlmod adopts a more relaxed version of the SemVer spec. The
+differences include:
+
+*   SemVer prescribes that the "release" part of the version must consist of 3
+    segments: `MAJOR.MINOR.PATCH`. In Bazel, this requirement is loosened so
+    that any number of segments is allowed.
+*   In SemVer, each of the segments in the "release" part must be digits only.
+    In Bazel, this is loosened to allow letters too, and the comparison
+    semantics match the "identifiers" in the "prerelease" part.
+*   Additionally, the semantics of major, minor, and patch version increases are
+    not enforced. However, see [compatibility level](#compatibility_level) for
+    details on how we denote backwards compatibility.
+
+Any valid SemVer version is a valid Bazel module version. Additionally, two
+SemVer versions `a` and `b` compare `a < b` if and only if the same holds when
+they're compared as Bazel module versions.
+
+## Version selection
+
+Consider the diamond dependency problem, a staple in the versioned dependency
+management space. Suppose you have the dependency graph:
+
+```
+       A 1.0
+      /     \
+   B 1.0    C 1.1
+     |        |
+   D 1.0    D 1.1
+```
+
+Which version of `D` should be used? To resolve this question, Bzlmod uses the
+[Minimal Version Selection](https://research.swtch.com/vgo-mvs){: .external}
+(MVS) algorithm introduced in the Go module system. MVS assumes that all new
+versions of a module are backwards compatible, and so picks the highest version
+specified by any dependent (`D 1.1` in our example). It's called "minimal"
+because `D 1.1` is the earliest version that could satisfy our requirements —
+even if `D 1.2` or newer exists, we don't select them. Using MVS creates a
+version selection process that is *high-fidelity* and *reproducible*.
+
+### Yanked versions
+
+The registry can declare certain versions as *yanked* if they should be avoided
+(such as for security vulnerabilities). Bazel throws an error when selecting a
+yanked version of a module. To fix this error, either upgrade to a newer,
+non-yanked version, or use the
+[`--allow_yanked_versions`](/reference/command-line-reference#flag--allow_yanked_versions)
+flag to explicitly allow the yanked version.
+
+## Compatibility level
+
+MVS's assumption about backwards compatibility works because it treats backwards
+incompatible versions of a module as a separate module. In terms of SemVer, that
+means `A 1.x` and `A 2.x` are considered distinct modules, and can coexist in
+the resolved dependency graph. This is, in turn, made possible by encoding the
+major version in the package path in Go, so there aren't any compile-time or
+linking-time conflicts.
+
+Bazel cannot provide such guarantees, so it needs the "major version" number in
+order to detect backwards incompatible versions. This number is called the
+*compatibility level*, and is specified by each module version in its `module()`
+directive. With this information, Bazel can throw an error when it detects that
+versions of the same module with different compatibility levels exist in the
+resolved dependency graph.
+
+## Overrides
+
+Specify overrides in the `MODULE.bazel` file to alter the behavior of Bazel
+module resolution. Only the root module can specify overrides — Bazel throws an
+error for dependency modules with overrides.
+
+Each override is specified for a certain module name, affecting all of its
+versions in the dependency graph. Although only the root module can specify
+overrides, they can be for transitive dependencies that the root module does not
+directly depend on.
+
+### Single-version override
+
+The [`single_version_override`](/rules/lib/globals#single_version_override)
+serves multiple purposes:
+
+*   With the `version` attribute, you can pin a dependency to a specific
+    version, regardless of which versions of the dependency are requested in the
+    dependency graph.
+*   With the `registry` attribute, you can force this dependency to come from a
+    specific registry, instead of following the normal [registry
+    selection](/external/registry#selecting_registries) process.
+*   With the `patch*` attributes, you can specify a set of patches to apply to
+    the downloaded module.
+
+These attributes are all optional and can be mixed and matched with each other.
+
+### Multiple-version override
+
+A [`multiple_version_override`](/rules/lib/globals#multiple_version_override)
+can be specified to allow multiple versions of the same module to coexist in the
+resolved dependency graph.
+
+You can specify an explicit list of allowed versions for the module, which must
+all be present in the dependency graph before resolution — there must exist
+*some* transitive dependency depending on each allowed version. After
+resolution, only the allowed versions of the module remain, while Bazel upgrades
+other versions of the module to the nearest higher allowed version at the same
+compatibility level. If no higher allowed version at the same compatibility
+level exists, Bazel throws an error.
+
+For example, if versions `1.1`, `1.3`, `1.5`, `1.7`, and `2.0` exist in the
+dependency graph before resolution and the major version is the compatibility
+level:
+
+*   A multiple-version override allowing `1.3`, `1.7`, and `2.0` results in
+    `1.1` being upgraded to `1.3`, `1.5` being upgraded to `1.7`, and other
+    versions remaining the same.
+*   A multiple-version override allowing `1.5` and `2.0` results in an error, as
+    `1.7` has no higher version at the same compatibility level to upgrade to.
+*   A multiple-version override allowing `1.9` and `2.0` results in an error, as
+    `1.9` is not present in the dependency graph before resolution.
+
+Additionally, users can also override the registry using the `registry`
+attribute, similarly to single-version overrides.
+
+### Non-registry overrides
+
+Non-registry overrides completely remove a module from version resolution. Bazel
+does not request these `MODULE.bazel` files from a registry, but instead from
+the repo itself.
+
+Bazel supports the following non-registry overrides:
+
+*   [`archive_override`](/rules/lib/globals#archive_override)
+*   [`git_override`](/rules/lib/globals#git_override)
+*   [`local_path_override`](/rules/lib/globals#local_path_override)
+
+## Repository names and strict deps
+
+The [canonical name](/external/overview#canonical_repository_name) of a repo
+backing a module is `{{ "<var>" }}module_name{{ "</var>" }}~{{ "<var>"
+}}version{{ "</var>" }}` (for example, `bazel_skylib~1.0.3`). For modules with a
+non-registry override, replace the `{{ "<var>" }}version{{ "</var>" }}` part
+with the string `override`. Note that the canonical name format is not an API
+you should depend on and is subject to change at any time.
+
+The [apparent name](/external/overview#apparent_repository_name) of a repo
+backing a module to its direct dependents defaults to its module name, unless
+the `repo_name` attribute of the [`bazel_dep`](/rules/lib/globals#bazel_dep)
+directive says otherwise. Note that this means a module can only find its direct
+dependencies. This helps prevent accidental breakages due to changes in
+transitive dependencies.
+
+[Module extensions](/external/extension) can also introduce additional repos
+into the visible scope of a module.
\ No newline at end of file
diff --git a/site/en/external/overview.md b/site/en/external/overview.md
new file mode 100644
index 0000000..fae1c1b
--- /dev/null
+++ b/site/en/external/overview.md
@@ -0,0 +1,190 @@
+Project: /_project.yaml
+Book: /_book.yaml
+
+# External dependencies overview
+
+{% include "_buttons.html" %}
+
+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.
+
+This article 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 with a `WORKSPACE` or `WORKSPACE.bazel` file, containing source
+files to be used in a Bazel build. Often shortened to just **repo**.
+
+### Main repository
+
+The repository in which the current Bazel command is being run.
+
+### Workspace
+
+The environment shared by all Bazel commands run in the same main repository.
+
+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//pac/kage: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//pac/kage: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](/extending/repo) for more information on how to write
+your own repository rules.
+
+The most common repo rules by far are
+[`http_archive`](/rules/lib/repo/http#http_archive), which downloads an archive
+from a URL and extracts it, and
+[`local_repository`](/reference/be/workspace#local_repository), which symlinks a
+local directory that is already a Bazel repository.
+
+### Fetching 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 will only fetch 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 will only re-fetch it if its definition has changed.
+
+### Directory layout
+
+After being fetched, the repo can be found in the subdirectory `external` in the
+[output base](/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>' }}
+```
+
+## Managing external dependencies with Bzlmod {:#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**](/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](/external/registry) — by default, the [Bazel Central
+Registry](https://bcr.bazel.build/){:.external}. 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**](/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){:.external}
+*   [Bazel External Dependencies Overhaul](https://docs.google.com/document/d/1moQfNcEIttsk6vYanNKIy3ZuK53hQUFq1b1r0rmsYVg/edit){: .external}
+    (original Bzlmod design doc)
+*   [BazelCon 2021 talk on Bzlmod](https://www.youtube.com/watch?v=TxOCKtU39Fs){: .external}
+
+## Defining repos with `WORKSPACE` {:#workspace-system}
+
+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.
+
+<!-- TODO(wyv): add link to WORKSPACE globals -->
+
+### 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`).
\ No newline at end of file
diff --git a/site/en/external/registry.md b/site/en/external/registry.md
new file mode 100644
index 0000000..cc8de14
--- /dev/null
+++ b/site/en/external/registry.md
@@ -0,0 +1,112 @@
+Project: /_project.yaml
+Book: /_book.yaml
+
+# Bazel registries
+
+{% include "_buttons.html" %}
+
+Bzlmod discovers dependencies by requesting their information from Bazel
+*registries*: databases of Bazel modules. Currently, Bzlmod only supports
+[*index registries*](#index_registry) — local directories or static HTTP servers
+following a specific format.
+
+## Index registry
+
+An index registry is a local directory or a static HTTP server containing
+information about a list of modules — including their homepage, maintainers, the
+`MODULE.bazel` file of each version, and how to fetch the source of each
+version. Notably, it does *not* need to serve the source archives itself.
+
+An index registry must follow the format below:
+
+*   `/bazel_registry.json`: A JSON file containing metadata for the registry
+    like:
+    *   `mirrors`: specifying the list of mirrors to use for source archives
+    *   `module_base_path`: specifying the base path for modules with
+        `local_repository` type in the `source.json` file
+*   `/modules`: A directory containing a subdirectory for each module in this
+    registry
+*   `/modules/$MODULE`: A directory containing a subdirectory for each version
+    of this module, as well as:
+    *   `metadata.json`: A JSON file containing information about the module,
+        with the following fields:
+        *   `homepage`: The URL of the project's homepage
+        *   `maintainers`: A list of JSON objects, each of which corresponds to
+            the information of a maintainer of the module *in the registry*.
+            Note that this is not necessarily the same as the *authors* of the
+            project
+        *   `versions`: A list of all the versions of this module to be found in
+            this registry
+        *   `yanked_versions`: A map of [*yanked*
+            versions](/external/module#yanked_versions) of this module. The keys
+            should be versions to yank and the values should be descriptions of
+            why the version is yanked, ideally containing a link to more
+            information
+*   `/modules/$MODULE/$VERSION`: A directory containing the following files:
+    *   `MODULE.bazel`: The `MODULE.bazel` file of this module version
+    *   `source.json`: A JSON file containing information on how to fetch the
+        source of this module version
+        *   The default type is "archive", representing an `http_archive` repo,
+            with the following fields:
+            *   `url`: The URL of the source archive
+            *   `integrity`: The [Subresource
+                Integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description){: .external}
+                checksum of the archive
+            *   `strip_prefix`: A directory prefix to strip when extracting the
+                source archive
+            *   `patches`: A map containing patch files to apply to the
+                extracted archive. The patch files are located under the
+                `/modules/$MODULE/$VERSION/patches` directory. The keys are the
+                patch file names, and the values are the integrity checksum of
+                the patch files
+            *   `patch_strip`: Same as the `--strip` argument of Unix `patch`.
+        *   The type can be changed to use a local path, representing a
+            `local_repository` repo, with these fields:
+            *   `type`: `local_path`
+            *   `path`: The local path to the repo, calculated as following:
+                *   If `path` is an absolute path, it stays as it is
+                *   If `path` is a relative path and `module_base_path` is an
+                    absolute path, it resolves to `<module_base_path>/<path>`
+                *   If `path` and `module_base_path` are both relative paths, it
+                    resolves to `<registry_path>/<module_base_path>/<path>`.
+                    Registry must be hosted locally and used by
+                    `--registry=file://<registry_path>`. Otherwise, Bazel will
+                    throw an error
+    *   `patches/`: An optional directory containing patch files, only used when
+        `source.json` has "archive" type
+
+## Bazel Central Registry
+
+The Bazel Central Registry (BCR) at <https://bcr.bazel.build/> is an index
+registry with contents backed by the GitHub repo
+[`bazelbuild/bazel-central-registry`](https://github.com/bazelbuild/bazel-central-registry){: .external}.
+You can browse its contents using the web frontend at
+<https://registry.bazel.build/>.
+
+The Bazel community maintains the BCR, and contributors are welcome to submit
+pull requests. See the [BCR contribution
+guidelines](https://github.com/bazelbuild/bazel-central-registry/blob/main/docs/README.md){: .external}.
+
+In addition to following the format of a normal index registry, the BCR requires
+a `presubmit.yml` file for each module version
+(`/modules/$MODULE/$VERSION/presubmit.yml`). This file specifies a few essential
+build and test targets that you can use to check the validity of this module
+version. The BCR's CI pipelines also uses this to ensure interoperability
+between modules.
+
+## Selecting registries
+
+The repeatable Bazel flag `--registry` can be used to specify the list of
+registries to request modules from, so you can set up your project to fetch
+dependencies from a third-party or internal registry. Earlier registries take
+precedence. For convenience, you can put a list of `--registry` flags in the
+`.bazelrc` file of your project.
+
+If your registry is hosted on GitHub (for example, as a fork of
+`bazelbuild/bazel-central-registry`) then your `--registry` value needs a raw
+GitHub address under `raw.githubusercontent.com`. For example, on the `main`
+branch of the `my-org` fork, you would set
+`--registry=https://raw.githubusercontent.com/my-org/bazel-central-registry/main/`.
+
+Using the `--registry` flag stops the Bazel Central Registry from being used by
+default, but you can add it back by adding `--registry=https://bcr.bazel.build`.
\ No newline at end of file