skip to content

Compare details.useVersion() and details.useTarget() inside an eachDependency rule. When would you reach for each?

level: middleimportance: must knowfreq 45%

answer

  1. useVersion = version only, same module
  2. useTarget = whole coordinate, can redirect
  3. useTarget accepts string/map notation
  4. pair with because() for insight
  5. substitution preferred for module swaps

basics

~10 s

useVersion 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 s

Both 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 lines
kotlin
configurations.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

for a junior

Know useVersion changes the version and useTarget changes the whole coordinate.

for a middle

Give concrete scenarios for each and mention because() for traceability.

for a senior

Explain when to prefer dependencySubstitution over useTarget and the reporting implications.

for a principal

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.

context