What is the ResolutionResult API in Gradle, and how does it differ from simply listing the files of a configuration?
answer
- incoming.resolutionResult
- allComponents / allDependencies
- graph vs files — decoupled
- selectionReason metadata-only
- getRoot() for true traversal
basics
~10 sResolutionResult gives the resolved dependency graph as components and dependencies, including versions chosen and reasons. Listing files gives only the resolved artifacts on disk, with no graph structure or selection metadata.
solid answer
~40 s`configuration.incoming.resolutionResult` exposes the **resolved dependency graph** — the model of which module versions were selected and why. Through `allComponents` and `allDependencies` you can walk every node (a `ResolvedComponentResult` with its `ModuleVersionIdentifier`, selection reason, and variant) and every edge (`DependencyResult`, which may be resolved or unresolved). This is purely the graph: it answers "what got selected and why," including conflict-resolution and constraint reasons. Resolving the **files** of a configuration (e.g. iterating `configuration` or using an `artifactView`) instead downloads/locates the actual artifacts. The two are decoupled: you can inspect the graph without downloading artifacts, and you can fetch a filtered set of artifacts via `artifactView` without touching the graph API. Use ResolutionResult for reporting/diagnostics; use files/artifactView when you need the bytes.
code
kotlin · 8 linestasks.register("printGraph") {
val rr = configurations.getByName("runtimeClasspath").incoming.resolutionResult
doLast {
rr.allComponents {
println("${'$'}{id.displayName} <- ${'$'}{selectionReason}")
}
}
}go deeper
Know that ResolutionResult describes the resolved dependency graph (which versions were picked), distinct from the actual files.
Explain incoming.resolutionResult, allComponents/allDependencies, ResolvedComponentResult vs DependencyResult, and that graph and files are decoupled.
Discuss selectionReason descriptors, true traversal from getRoot(), and the performance cost of eager access at configuration time.
Frame ResolutionResult as the foundation for org-wide dependency governance/reporting tooling (license scans, version dashboards) built without forcing artifact downloads.
## Two distinct outputs of resolution When Gradle resolves a `Configuration`, it produces two related but separate things: 1. **A dependency graph** — the abstract model of which module versions were selected, the edges between them, and *why* each was chosen (requested version, conflict resolution, constraint, forced, etc.). 2. **A set of artifacts** — the actual files (jars, AARs, etc.) produced by resolving the variants of those components. The `ResolutionResult` API exposes the **graph**, not the files. ## Accessing the graph ```kotlin val result = configurations.getByName("runtimeClasspath") .incoming.resolutionResult result.allComponents { // ResolvedComponentResult println("${'$'}{id} selected because ${'$'}{selectionReason}") } result.allDependencies { // DependencyResult when (this) { is ResolvedDependencyResult -> println("resolved -> ${'$'}{selected.id}") is UnresolvedDependencyResult -> println("FAILED ${'$'}{requested}: ${'$'}{failure.message}") } } ``` Key types: - **`ResolvedComponentResult`** — a node. Carries `id` (a `ComponentIdentifier`), `moduleVersion` (`ModuleVersionIdentifier`), `selectionReason` (`ComponentSelectionReason`, with descriptors explaining conflict resolution/constraint/forced), and the `variants` selected. - **`DependencyResult`** — an edge; subtype `ResolvedDependencyResult` (has `selected` node + `requested`) or `UnresolvedDependencyResult` (has `failure`). - **`getRoot()`** — the synthetic root component representing the configuration itself; you can traverse `dependencies` from it for a true graph walk instead of the flat `allComponents`/`allDependencies` callbacks. ## Why it is decoupled from files The graph can be queried **without downloading any artifact** — selection is metadata-only. This makes ResolutionResult ideal for dependency-report tasks (`dependencies`, `dependencyInsight` are built on top of it), license scanners, and build-logic that needs to reason about versions. Conversely, fetching files (iterating the configuration or using an `artifactView`) can require downloading and may fail for reasons unrelated to graph selection (e.g. a missing classifier). ## Laziness The callbacks (`allComponents`, etc.) trigger resolution when accessed, so accessing them during configuration time forces eager resolution and hurts build performance. Prefer accessing them at **execution time** inside a task action, or wrap the work in a `Provider` so it stays lazy. ## When to use which - Reporting "what version won and why" → ResolutionResult graph. - Need the actual jars (e.g. to build a fat jar, copy, classpath) → resolve files / `artifactView`.
- Why might accessing resolutionResult.allComponents in the configuration phase hurt build performance?It forces the configuration to resolve eagerly during configuration time, defeating lazy resolution and slowing every build invocation, even ones that don't need that configuration.
- How would you find why a particular version was selected?Walk allComponents, find the matching ResolvedComponentResult, and read selectionReason.descriptions — each ComponentSelectionDescriptor states the cause (conflict resolution, constraint, forced, etc.). dependencyInsight uses the same data.
saying these in an interview costs you the question
- Claiming ResolutionResult returns the jar files — it returns the graph model, not artifacts.
- Saying you must download artifacts to inspect selected versions — graph inspection is metadata-only.