skip to content

Resolution and Conflicts

What Gradle does when two paths demand different versions: default conflict resolution, forcing and constraints, rewriting rules, substitution, capabilities, and locking. This is the area that separates Gradle users from Gradle debuggers.

on this pageshow

explore

questions

page 2 of 2

What are the directionality and version semantics of a replacedBy rule? Does it pin or introduce the replacement module's version?

level: seniorimportance: should knowfreq 22%

basics

~20 s

It is one-directional: old is replaced by new. It never pins or introduces the new module's version — the replacement is only chosen if it is already in the graph, and its version is resolved by Gradle's normal rules.

open as a page

How does module replacement differ from dependency substitution, and when would you choose one over the other?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Substitution unconditionally swaps one selector for another module/project. Module replacement only states that two coordinates are the same logical library, so the old one is evicted during conflict resolution if both appear. Use replacement for renamed libraries, substitution for forced swaps.

open as a page

How do you wire the artifacts of a configuration into a custom task lazily, and why does laziness matter here?

level: seniorimportance: should knowfreq 30%

basics

~10 s

Use configuration.incoming.artifactView{...}.artifacts.artifactFiles (a lazy FileCollection) as the task's @InputFiles. Resolution then happens at execution time, not configuration time, keeping builds fast and configuration-cache compatible.

open as a page

How would you programmatically determine why Gradle selected a particular version of a dependency, using the ResolutionResult API?

level: seniorimportance: should knowfreq 35%

basics

~10 s

Walk the graph via incoming.resolutionResult.allComponents, find the ResolvedComponentResult for the module, and read its selectionReason — its descriptors explain the cause (conflict resolution, constraint, forced, etc.).

open as a page

Engineers sometimes read a project extension property at the top of an eachDependency rule and are surprised by the value or by configuration cache warnings. Explain the configuration-time vs resolve-time subtlety and how to capture inputs safely.

level: seniorimportance: should knowfreq 25%

basics

~20 s

The eachDependency closure runs at resolve time, but you register it at configuration time. Capturing live project state inside it can read stale values or break the configuration cache. Resolve inputs into a Provider/local val up front instead.

open as a page

On a large multi-module build you must decide between eachDependency rules and Gradle's more declarative mechanisms for controlling versions. How do you reason about when eachDependency is the right tool versus a smell?

level: seniorimportance: should knowfreq 20%

basics

~20 s

eachDependency is an imperative per-module callback — great for conditional or computed rewrites, but harder to read and reason about at scale. For broad version policy, prefer declarative constraints or a platform; reserve eachDependency for cases needing logic.

open as a page

How do you substitute a dependency while preserving or targeting a specific variant, classifier, or capability?

level: seniorimportance: should knowfreq 28%

basics

~10 s

Use the variant-aware substitution DSL: substitute(module(...)).using(project(...)).withClassifier(...) or attach capabilities/attributes via variant { ... }, so the substitute resolves to the correct artifact instead of failing on a missing variant.

open as a page

Using artifactView's componentFilter, how would you separate project (local) artifacts from external module artifacts, and when is that useful?

level: juniorimportance: nice to knowfreq 20%

basics

~10 s

Set componentFilter { id -> id is ProjectComponentIdentifier } to keep only local project artifacts, or ModuleComponentIdentifier for external ones. Useful for fat-jar/relocation logic that should treat your own code differently from third-party libs.

open as a page

How does `resolutionStrategy.failOnVersionConflict()` interact with `force` and strict constraints, and when would you enable it?

level: seniorimportance: nice to knowfreq 24%

basics

~20 s

failOnVersionConflict() makes Gradle fail whenever two versions of a module are requested, instead of silently picking the highest. force resolves such conflicts and avoids the failure; you enable it to surface every version disagreement and pin them deliberately.

open as a page

How do you publish a component so that two of its optional features are mutually exclusive via capabilities, and what's the difference between feature variants and a capability conflict?

level: principalimportance: nice to knowfreq 18%

basics

~20 s

When publishing, declare a capability on a variant via the Java library's registerFeature or by adding capabilities to outgoing configurations. If you give two alternative implementations the same capability, consumers can pick only one — Gradle enforces mutual exclusivity at resolution.

open as a page

How would you roll out dependency locking across a large multi-module build, and what scope and policy decisions matter?

level: principalimportance: nice to knowfreq 22%

basics

~10 s

Decide which configurations to lock (often all resolvable ones), generate per-project lockfiles, commit them, and enforce regeneration in CI. Use STRICT mode to forbid unlocked resolution, and define a standard --update-locks workflow for upgrades.

open as a page

showing 31–41 of 41