// project/build.gradle
ext {
commonsIoVersion = '2.5'
…and you don’t change anything in the sub-modules? Then the sub-modules’ builds will fail. Won’t they?
So doesn’t that mean that they’re still coupled?
I think the approach you’ve chosen is semantically exactly the same approach that I suggested.
The only difference is the first approach expresses the intention explicitly. Whereas the second approach could be prone to somebody removing that ext
block from the base project; not knowing that the sub-modules need it to be there for their builds to succeed.
In my opinion, the subprojects{}
block makes it obvious to everybody that if the stuff inside it is fooled with, it will have a knock-on effect.
Do you see what I mean?
Coupling, as explained in the link that I shared, has a specific meaning, not what the general term “coupling” means:
Gradle allows any project to access any other project during both the configuration and execution phases. While this provides a great deal of power and flexibility to the build author, it also limits the flexibility that Gradle has when building those projects. For instance, this effectively prevents Gradle from correctly building multiple projects in parallel, configuring only a subset of projects, or from substituting a pre-built artifact in place of a project dependency.
Two projects are said to be decoupled if they do not directly access each other’s project model. Decoupled projects may only interact in terms of declared dependencies: project dependencies and/or task dependencies. Any other form of project interaction (i.e. by modifying another project object or by reading a value from another project object) causes the projects to be coupled. The consequence of coupling during the configuration phase is that if gradle is invoked with the ‘configuration on demand’ option, the result of the build can be flawed in several ways. The consequence of coupling during execution phase is that if gradle is invoked with the parallel option, one project task runs too late to influence a task of a project building in parallel. Gradle does not attempt to detect coupling and warn the user, as there are too many possibilities to introduce coupling.
A very common way for projects to be coupled is by using configuration injection. It may not be immediately apparent, but using key Gradle features like the allprojects
and subprojects
keywords automatically cause your projects to be coupled.
Why don’t use Gradle Dependency Constraints as a dependency manager?
dependencies {
implementation("org.apache.httpcomponents:httpclient")
constraints {
implementation("org.apache.httpcomponents:httpclient:4.5.3") {
because("previous versions have a bug impacting this application")
implementation("commons-codec:commons-codec:1.11") {
because("version 1.9 pulled from httpclient has bugs affecting this application")
If I understand the issue correctly, it looks like gradle resolved your exact problem in gradle 6.0 with the java-platform plugin. I know your question was before gradle 6, but for those of us coming to this question after gradle 6, check it out: https://gradle.org/whats-new/gradle-6/ https://www.baeldung.com/gradle-6-features