Declaring Dependency Constraints
Version declarations (including ranges) only affect the dependencies you declare directly. To control versions of transitive dependencies, use dependency constraints.
A dependency constraint sets version requirements for a module without adding that module as a dependency. When the module is pulled in, the constraint participates in version conflict resolution just like a declared dependency version:
-
Constraints are not strict by default (they usually express "at least this version").
-
You can make them strict or use rich versions (e.g., ranges,
prefer,reject,strictly) when needed.
| Use constraints when you want to control versions centrally and avoid adding extra dependencies just to force a version. |
You can declare constraints:
-
Alongside dependencies in a single project (scoped to the same configuration buckets like
implementation,runtimeOnly,testImplementation, etc.). -
Centrally in a platform (recommended for multi-project builds) using the
java-platformplugin:
plugins {
`java-platform`
}
dependencies {
constraints {
// Platform declares some versions of libraries used in subprojects
api("commons-httpclient:commons-httpclient:3.1")
api("org.apache.commons:commons-lang3:3.8.1")
}
}
plugins {
id 'java-platform'
}
dependencies {
constraints {
// Platform declares some versions of libraries used in subprojects
api 'commons-httpclient:commons-httpclient:3.1'
api 'org.apache.commons:commons-lang3:3.8.1'
}
}
You cannot declare constraints in version catalogs.
Declaring constraints alongside direct dependencies
Constraints are scoped by bucket configurations (e.g., implementation, runtimeOnly).
They apply whenever that dependency is encountered during resolution.
The constraints {} block is used within the dependencies {} block to declare these constraints:
plugins {
`java-platform`
}
dependencies {
constraints {
api("commons-httpclient:commons-httpclient:3.1")
runtime("org.postgresql:postgresql:42.2.5")
}
}
plugins {
id 'java-platform'
}
dependencies {
constraints {
api 'commons-httpclient:commons-httpclient:3.1'
runtime 'org.postgresql:postgresql:42.2.5'
}
}
-
api("commons-httpclient:commons-httpclient:3.1"): ensures ≥ 3.1 forapi. -
runtime("org.postgresql:postgresql:42.2.5"): ensures ≥ 42.2.5 forruntime.
If multiple requirements exist, Gradle picks a version that satisfies all. If none exists, resolution fails with an error describing the conflict.
Adding constraints on transitive dependencies
Use constraints to select transitive modules without introducing them as direct dependencies:
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")
}
}
}
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 commons-codec isn’t brought in transitively, the constraint is a no-op (it doesn’t add the module).
If it is brought in, the constraint guides the version selection.
Rich versions and strict versions for constraints
You can attach rich versions to constraints:
dependencies {
constraints {
implementation("com.google.guava:guava") {
version {
strictly("33.1.0-jre")
}
because("avoid older versions with known issues")
}
}
}
dependencies {
constraints {
implementation("com.google.guava:guava") {
version {
strictly("33.1.0-jre")
}
because("avoid older versions with known issues")
}
}
}
Transitivity of constraints
Dependency constraints are transitive.
If library A depends on library B, and library B declares a constraint on module C, that constraint will affect the version of module C that library A depends on.
For example, if library A depends on module C version 2, but library B declares a constraint on module C version 3, library A will resolve version 3 of module C.
Publishing constraints
Dependency constraints are only published when using Gradle Module Metadata. This means they are fully supported only when both publishing and consuming modules with Gradle.
If modules are consumed with Maven or Ivy, the constraints may not be preserved.