Compare details.useVersion() and details.useTarget() inside an eachDependency rule. When would you reach for each?
answer
- useVersion = version only, same module
- useTarget = whole coordinate, can redirect
- useTarget accepts string/map notation
- pair with because() for insight
- substitution preferred for module swaps
basics
~10 suseVersion changes only the version of the requested module, keeping its group and name. useTarget replaces the whole coordinate (group:name:version), letting you redirect one module to an entirely different one.
solid answer
~40 sBoth operate on the `DependencyResolveDetails` Gradle hands your `eachDependency` rule. `details.useVersion("2.17.1")` keeps the requested group and name and only swaps the version — use it to normalize or pin a version. `details.useTarget("com.new:artifact:1.4")` (or a map / dependency notation) replaces the entire coordinate — use it to redirect a module to a relocated or renamed artifact, e.g. when a library changed its groupId or you want to substitute a fork. Both should ideally pair with `details.because("reason")` so the change shows up in `./gradlew dependencyInsight`. The distinction: `useVersion` is version-only and stays within the same module identity; `useTarget` can cross module boundaries entirely. Note that for whole-module swaps, `dependencySubstitution` is the more declarative, capability-aware alternative — `useTarget` is the older imperative path.
code
kotlin · 14 linesconfigurations.all {
resolutionStrategy.eachDependency {
when {
requested.name == "guava" -> {
useVersion("33.2.1-jre") // version only
because("normalize Guava")
}
requested.group == "old.group" -> {
useTarget("new.group:lib:1.4.0") // whole coordinate
because("relocated artifact")
}
}
}
}go deeper
Know useVersion changes the version and useTarget changes the whole coordinate.
Give concrete scenarios for each and mention because() for traceability.
Explain when to prefer dependencySubstitution over useTarget and the reporting implications.
Weigh imperative rewrites vs declarative platform/substitution governance across many repos.
## The two mutators Inside an `eachDependency` rule you receive a `DependencyResolveDetails`. The two ways to alter the outcome are `useVersion` and `useTarget`. ### useVersion(String) ```kotlin configurations.all { resolutionStrategy.eachDependency { if (requested.name == "guava") { useVersion("33.2.1-jre") because("single Guava version across the graph") } } } ``` Keeps `requested.group` and `requested.name`; only the version changes. The module identity (group:name) is unchanged, so this is a pure version rewrite. Ideal for: pinning a transitive, normalizing a family of artifacts to one version, or upgrading a vulnerable transitive in place. ### useTarget(Object) ```kotlin configurations.all { resolutionStrategy.eachDependency { if (requested.group == "old.group" && requested.name == "lib") { useTarget("new.group:lib:1.4.0") because("library relocated to a new groupId") } } } ``` Accepts a `"group:name:version"` string, a map (`mapOf("group" to ..., "name" to ..., "version" to ...)`), or other dependency notation. It replaces the **whole coordinate**, so you can change group, name, and version at once — redirecting to a different module entirely. ## Choosing between them | Goal | Use | |------|-----| | Pin/normalize a version, same module | `useVersion` | | Redirect to a renamed/relocated/forked module | `useTarget` | | Whole-module swap with capability/variant awareness | prefer `dependencySubstitution` (declarative) | ## Why pair with because() `details.because("...")` records the rationale. It surfaces in `./gradlew dependencyInsight --configuration runtimeClasspath --dependency <name>`, so six months later the team can see *why* a version was forced or a module redirected, instead of finding a mysterious rewrite. ## Caveat `useTarget` for whole-module replacement predates the richer `dependencySubstitution` DSL. For new code, module-to-module swaps are usually cleaner and more capability-aware via substitution; `useVersion` inside `eachDependency` remains the natural tool for plain version rewrites.
- Can useTarget change the group of a dependency?Yes. useTarget replaces the entire coordinate, so group, name, and version can all change in one call.
- Why might dependencySubstitution be preferred over useTarget for a module swap?Substitution is a declarative, capability/variant-aware DSL with clearer reporting and project-substitution support, whereas useTarget is the older imperative per-dependency path.
saying these in an interview costs you the question
- Saying useVersion can change the group or name — it cannot.
- Claiming useTarget only changes the version — it replaces the full coordinate.