As projects start to be more complex and modularized, keeping all the dependencies in sync and updating them becomes a hard and annoying task. To solve this, we have a few alternatives and a new one was recently launched by Gradle to make our lives easier.
Gradle introduced in version 7.0 a new feature called Version Catalog. It represents a list of type-safe dependencies to be used across the projects. It is also very flexible and takes advantage of what Gradle currently has to offer. In this article, we will take a look at why using, how to apply it in an Android project and some points that are important to know before diving in.
The Version Catalog is a very flexible solution that takes advantage of existing gradle features and allows us to do even more than the alternatives. One example is the ability to create
bundles which allow adding a single
implementation() line with a set of libraries in our Gradle File.
Version Catalog files are shareable, so it’s even easier to have a standard configuration not only inside it but across multiple projects. The flexibility also supports third-party plugins to automatically update the versions for the latest ones, if we want.
Also, in addition to composite builds, it performs better in comparison with the
buildSrc solution. For instance with
buildSrc, when we increment a version number the build is cleaned and needs to be rebuilt. This is not the case for Version Catalog. For more details about performance, please take a look at this great article by Josef Raska. For more insights, This is a great Twitter thread to follow.
In order to configure the Version Catalog in our project, a set of simple steps are required.
1. Create the libs.versions.toml file
libs.versions.toml file is the file that contains all the dependency definitions, such as
It’s worth mentioning that all the dependency alias are normalized by Gradle. It means that every alias that has
. will be updated to use
.instead. For instance the alias
compose.ui will be normalized as
Keep in mind that it’s also possible to define the Version Catalogs in the
settings.gradle(.kts), however for clarity we are showing only with the TOML file. For more information about this and other ways to define your dependencies, please take a look at the official docs.
2. Create a dedicated module for plugins
Since we are using composite builds with Version Catalog, we need a dedicated module. The module does not need a specific name, but just make sure that it won’t conflict with the existing ones in your project. In our example, let’s call it
This module needs to contain at least two files: a
settings.gradle(.kts). The first one is used for regular Gradle configuration and the other is used to link up our
libs.versions.toml file with the Version Catalog feature.
3. Setup Composite Build
Now that we have our Version Catalog set, we need to set up the composite build to link this configuration with our project. In order to achieve that, we need to open our project’s
settings.gradle file and include a few lines:
The code above sets the plugin management to not only look for dependencies in the remote repositories but also search for them in our
If your project is using a Gradle version below
7.2you will need to add a new feature preview activation on the
4. Use the Version Catalog
Finally, after this setup, we are able to use the dependencies in our Gradle files.
In addition to the points already mentioned about Version Catalog, there are a couple of things that are good to know.
Automatically update versions
One of the advantages of the Version Catalog is the ability to use tools to automatically update them. For projects on GitHub, RenovateBot is a great tool to integrate into your pipeline. This bot reads your
libs.versions.toml and automatically creates Pull Requests to update your dependencies.
My pipeline has a set of unit and instrumented tests, so I’m confident that the new version is compatible and I just click the merge button. If the tests fail, I just update the PR with the API changes and it’s good to go.
However, if your project does not support that plugin, a good alternative is the Version Catalog Update Plugin to directly apply to the project’s Gradle file. Both plugins are widely configurable and help us keep the project dependencies fresh.
No support for precompiled script plugins
One of the points of attention from Version Catalog is that the dependencies and versions are not visible in precompiled script plugins. In other words, the dependencies declared on
libs.versions.toml will be visible on the
build.gradle from all your modules, but not for custom/precompiled ones.
Let’s say that we have dozens of
library modules on our project and want all of them to have the same basic dependencies. We could create a
library_dependencies.gradle containing them all and just apply it to the appropriate modules.
Unfortunately, this new Gradle file won’t be able to find the appropriate dependency due to some limitations. One way to workaround this issue is to create an extension function to manually expose the dependency.
Now instead of trying to directly access the Version Catalog, we manually access the
libs reference and the
implementation function will access our extension function and work properly.
One of the drawbacks of this solution is that it’s type unsafe since we are using Strings to find the dependencies rather than generated code. For more information about this behaviour, I highly recommend this GitHub Issue with an extensive discussion about this topic.
The Version Catalog is a great new way to handle dependency management on our projects. It makes the maintenance of both libraries and versions easier and also allows all the flexibility that Gradle has to offer. Some Android projects already started migrating and we will start to see more and more code, examples and improvements on this amazing feature.
As usual, I would love to share more complex code to help you in your studies. The first Pull Request it’s on my personal project, Alkaa, which migrates from
buildSrc to Version Catalog. It also adds a few JVM Convention Plugins to help avoid duplication, but this is a topic for the next article. 🙂
Also, there are two PRs from amazing projects that I used a lot as examples when I was doing the migration. The first one is ShoppingApp by Sam Edwards and Voice by Paul Woitaschek. A huge thanks to both for their amazing contributions! ❤️
The code used in this article is available on GitHub, where you can see step by step each part of the process:
The official Gradle documentation also has great examples and insights on how to improve dependency management on our projects. For more deep and informal content, this article from Cédric Champeau is great. And last but not least, the official Now In Android by Google also uses the Version Catalog.