Skip to content
A Maven dependency graph generator for Bazel
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


Latest release Build Status codecov

Yet another Maven dependency graph generator for Bazel.

This WORKSPACE will provide deps_workspace_generator_rule rule and artifact macro which will automatically generate a set of targets that can be used as dependencies based on a given list of Maven coordinates. The rule will output the dependencies-graph to a file (similar to Yarn's lock-file).


  • Transitively resolves all dependencies from a given list of Maven dependencies, and manages version conflicts - ensuring that only one version of each artifact is available in the dependencies graph.
  • Generates repository-rules for all remote artifacts.
  • Generates required Java rule (with transitive dependencies).
  • Automatically detects which rule-type to create for a given dependency:
    • aar_import for Android artifacts.
    • java_plugin + java_library for annotation-processors. More about this here.
    • kt_jvm_import + kt_jvm_library or java_import for Kotlin modules. More about this here.
    • java_import for anything else.
  • Support custom Maven repo URLs and locking dependency for a Maven repository.
  • Adds licenses data to java_import rules, if license is declared in the artifact's POM file.
  • Adds srcjar if sources available in the Maven repository.
  • Handle POM options:
    • Profiles and placeholders.
    • Version-specification.
    • Dependencies that do not have POM.
    • Exports the Maven coordinate as a tag in the java_import rule. This can help with Bazel's pom_file rule.
  • Calculates sha256 for each remote artifact.
  • Produces a lock file that describes the dependency graph. This file should be checked into your repo.


Unlike other build systems, Bazel does not provide a dependency management service as part of the build and does not provide a way to specify a Maven dependency (which will be resolved transitively) and be available during compilation.
There are several attempts to solve this problem (such as sync-deps, gmaven, rules_jvm_external, migration-tooling, maven-rules and bazel-deps), but some do not support Kotlin or Android, some do not support customized Maven repositories, etc.



Add this repository to your WORKSPACE (set bazel_mvn_deps_version to the latest release or, if you are adventurous, commit):

mabel_version = "0.5.4"
    name = "mabel",
    urls = ["" % mabel_version],
    type = "zip",
    strip_prefix = "mabel-%s" % mabel_version

load("@mabel//resolver/main_deps:dependencies.bzl", generate_bazel_mvn_deps_workspace_rules = "generate_workspace_rules")

target definition

In your module's BUILD.bazel file (let's say resolver/BUILD.bazel) load the dependencies rule and artifact macro:

load("@mabel//rules/maven_deps:maven_deps_workspace_generator.bzl", "deps_workspace_generator_rule", "artifact")

And define a target for resolving dependencies:

deps_workspace_generator_rule(name = 'main_deps',
    maven_deps = [
    generated_targets_prefix = "main_deps___")

In this example above we defined the target //resolver:main_deps with 4 maven dependencies:

  • org.apache.commons:commons-lang3:jar:3.8.1 - here we are specifically asking for jar classifier. In most cases we don't need to do that.
  • - which is an annotation-processor.

Resolving the dependency graph

To generate the transitive rules for the required maven_deps, you'll run the target:

bazel run //resolver:main_deps

This will retrieve all the transitive dependencies and resolve conflicts. We will store the resolved dependencies graph (Bazel rules) in the file resolver/main_deps/dependencies.bzl, and will create a folder-structure matching all the deps:

                        BUILD.bazel (with alias guava -> //resolver:main_deps___com_google_guava__guave)
                            BUILD.bazel (with alias jsr305 -> //resolver:main_deps___com_google_code_findbugs__jsr305)
                            BUILD.bazel (with alias auto-value -> //resolver:main_deps___com_google_auto_value__auto_value)
                        BUILD.bazel (with alias commons-lang3 -> //resolver:main_deps___org_apache_commons__commons_lang3)

You'll noticed that there's a prefix main_deps___ to all targets, this prefix allows you to generate several graphs for different cases (for example, compile vs annotation-processor stages). It was added because we specified generated_targets_prefix = "main_deps___" in the target definition.
This file will need to be checked into your repository, same as Yarn's lock file.
NOTE: If you do not wish the rule to generate the sub-folders, you can add generate_deps_sub_folder = False to your artifact target definition.

Using the generated Maven dependencies

First, you'll need to register all the repository rules for the remote maven artifacts. In your WORKSPACE file, add:

load("//resolver/main_deps:dependencies.bzl", main_mabel_deps_rules = "generate_workspace_rules")

And, in the same module you declared deps_workspace_generator_rule (in our example //resolver) add to the BUILD.bazel file:

load("//resolver/main_deps:dependencies.bzl", main_generate_transitive_dependency_targets = "generate_transitive_dependency_targets")

This will make the rules available in any target defined in that BUILD.bazel file as //resolver:mvn_main___XXX:

  • as //resolver:main_deps___com_google_guava__guava
  • org.apache.commons:commons-lang3:jar:3.8.1 as //resolver:main_deps___org_apache_commons__commons_lang3
  • as //resolver:main_deps___com_google_code_findbugs__jsr305

Or, you can use the sub-folder structure (IDEs find this easier to auto-complete):

  • as //resolver/main_deps/com/google/guava/guava
  • org.apache.commons:commons-lang3:jar:3.8.1 as //resolver/main_deps/org/apache/commons/commons_lang3
  • as //resolver/main_deps/com/google/code/findbugs/jsr305

Rule configuration


This rule will merge the dependencies into one, version-conflict-resolved, dependencies graph ensuring you do not have conflicting versions of an artifact in your classpath.

  • maven_deps: List of artifact targets representing a Maven coordinate.
  • generate_deps_sub_folder: Default True. Will create sub-folders with BUILD.bazel file for each dependency.
  • calculate_sha: Default True. Will calculate the sha256 value of each remote artifact.
  • fetch_srcjar: Default False. Will also try to fetch sources jar for each dependency.
  • generated_targets_prefix: A prefix to add to all generated targets. Default is an empty string, meaning no-prefix. This might be useful if you want to generate several, unrelated, graphs.
  • output_graph_to_file: If set to True, will output the graph to dependencies.txt. Default is False.

maven_dependency_graph_resolving_rule or artifact

This rule declares a Maven dependency to be resolved and import into your WORKSPACE.

  • coordinate: Maven coordinate in the form of group-id:artifact-id:version.
  • maven_exclude_deps: List of Maven dependencies which should not be resolved. You can omit the version or both artifact-id:version.
  • repositories: List of URLs that point to Maven servers. The default list includes Maven-Central.

Real Examples

You can find a few examples under the examples/ folder in this repo. These examples are built as part of the CI process, so they represent a working use-case.
NOTE - There is an ongoing issue with kt_jvm_import. But, Kotlin still works with java_import.

Detected rules

Android AARs

If the resolved artifact is an aar file, we'll create aar_import target.


For dependencies that are detected as annotation-processors we are creating a java_plugin rule for each detected processor_class, and then wrap all of these rules in a java_library rule that exports the plugins.
In the example above we included, which is a Java annotation-processor, we create the following rules:

  • //resolver:main_deps___com_google_auto_value__auto_value - which is a java_library without any annotation-processing capabilities.
  • //resolver:main_deps___com_google_auto_value__auto_value___processor_class_0..4 - which is a java_plugin with annotation-processing capabilities using the first detected processor-class. Four of those, because there are four such classes.
  • //resolver:main_deps___com_google_auto_value__auto_value___generates_api___processor_class_0..4 - the same as before, but generate API.
  • //resolver:main_deps___com_google_auto_value__auto_value___processor_class_all - a java_library that groups all the processors that do not generate API.
  • //resolver:main_deps___com_google_auto_value__auto_value___generates_api___processor_class_all - same as before, but generates API.

Please, read the Bazel docs about which variant you want.
Also, since we are wrapping the java_plugin rules in a java_library rules, you should add them to the deps list of your rule and not to the plugins list, unless you are directly using the X___processor_class_Y variant in which case you should use it in the plugins field.


NOTE : I recommend not to provide kt rule-impl to the macro, and just use regular java_import. See relevant issue.

For Kotlin, we create a kt_jvm_import for each artifact, and then wrap it (along with its deps) in a kt_jvm_library. Your rule depends on the kt_jvm_library.

If your dependencies contain Kotlin rules, you'll need to pass the kt rule-impl to the transitive rules generation macro (in the example above, it is generate_migration_tools_transitive_dependency_rules):

load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_import", "kt_jvm_library")

load("//resolver/main_deps:dependencies.bzl", main_generate_transitive_dependency_targets = "generate_transitive_dependency_targets")
main_generate_transitive_dependency_targets(kt_jvm_import = kt_jvm_import, kt_jvm_library = kt_jvm_library)

Note: If you decide not to provide kt_* implementations, we will try to use java_import instead. It should be okay.
NOTE: Although the mechanism above exists, I could not make it work. Either, you know how to fix this, or just use the regular java_import (by not supplying kt_jvm_*).
Another NOTE: There is a problem with this, at the moment: kt_jvm_library in master does not allow no-source-libraries. So, until the fix is merged, you can use my branch of the rules:

rules_kotlin_version = "no-src-support"
    name = "io_bazel_rules_kotlin",
    urls = ["" % rules_kotlin_version],
    type = "zip",
    strip_prefix = "rules_kotlin-%s" % rules_kotlin_version

load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kotlin_repositories", "kt_register_toolchains")
You can’t perform that action at this time.