Managing dependencies in multi-project builds with gradle

Arran Lomas
Freelancer Engineering & Data Science
3 min readDec 13, 2017

This article discusses the benefits of having multi-project builds, the drawbacks of this structure and offers a possible solution to one of the main problems with multi-project builds — managing dependencies and versioning of third party libraries. The full example repo can be found here.

It is common practice to structure your project so items are packaged by features rather than layers. For example, if you were using mvp, you would place your login view with your login presenter, as opposed to bundling all your views together and your presenters together. There is a number of reasons for why this is good practice and a great article on this can be found here.

In large or complex projects this can be taken a step further and layers or features can be broken into sub-projects or modules, the official gradle docs do a good job of describing this process. This can further help reduce coupling and increase the separation of concerns (kotlin internal classes can really help with this in multi-project builds).

For example, let’s say you have a core module which is responsible for connecting to your api, persistence and a place for your models, then on top of that some feature modules, and on top of that an app module. So you may end up with dependencies that look like the following:

These modules will often have common dependencies and variables (think android support libraries, Kotlin, RxJava etc.), in larger projects it can become difficult to managing these dependencies to avoid dependency conflicts and other potentially strange and difficult to debug issues.

A possible solution is to create a file that is shared between all sub-projects and declares all of your third party dependencies, you can then use this file in all your sub-projects to add the dependencies, meaning you can manage your dependencies in one place.

First we need to create a file to declare your dependencies, for the sake of this example I called it dependencies.gradle and placed it in the root gradle folder, in here we are going to declare some dependencies as below.

The next step is to go into the project root gradle file and tell the project we have added a new gradle file. This is done by adding the following to the top of your root build.gradle file

apply from: ‘gradle/dependencies.gradle’

The project root build.gradle now looks something like this:

Now you can begin to add the dependencies into the sub-projects. To do this you declare a variable in your sub-project build.gradle to access the root project extensions. This is done with the following line:

def globalConf = rootProject.ext 

Next you have to create a variable that contains the map of dependencies that we declared in the dependencies.gradle file. To do this we add the following in the dependencies block.

Map<String, String> dependencies = globalConf.commonDependencies

Finally we can use the dependencies by doing

compile dependencies.kotlinStdLib

The full gradle file for one of the sub-projects now looks something like the following:

And thats it! You can now manage all your sub-project dependencies from one file.

I have found this method of managing dependencies to be extremely useful for avoiding dependency conflicts. However, there are some drawbacks, the subproject now depends on a file outside of it own project scope, this means if you take one of the subprojects out of the root project, you will then have ensure it can resolve its dependencies via another dependencies.gradle file.

--

--