There are two different 'dependency graphs' in Gradle. What is the difference between the task graph and the dependency (artifact) resolution graph?
answer
- task graph = what runs
- artifact graph = which jars
- dry-run + circular = task graph
- dependencies / dependencyInsight = artifact graph
- project deps inject inferred task edges
basics
~20 sThe task graph is the DAG of tasks Gradle will execute (e.g. compile before test). The dependency/artifact graph is the resolved tree of external modules/jars for a configuration (e.g. via dependencies). They are separate concepts solving separate problems.
solid answer
~50 sGradle has **two** graphs that are easy to conflate. The **task graph** is the DAG of `Task` instances derived from the requested tasks plus their dependencies/ordering — it answers *what runs and in what order*. The **dependency (artifact) resolution graph** is the resolved set of external **modules and their transitive dependencies** for a given `Configuration` — it answers *which jars/components end up on a classpath*, resolving versions via conflict resolution, constraints, and metadata. This topic concerns the **task** graph: `--dry-run` previews it and circular-dependency errors come from it. The artifact graph is inspected with tools like `gradle dependencies` / `dependencyInsight` and lives under dependency management. They interact only indirectly: resolving a configuration may trigger producing tasks (e.g. building a project dependency's jar), and that wiring shows up as inferred task dependencies — but the two graphs are computed by different subsystems.
code
bash · 6 lines# Task graph (this topic)
gradle test --dry-run
# Artifact / dependency-management graph (different subsystem)
gradle dependencies --configuration runtimeClasspath
gradle dependencyInsight --dependency slf4j-api --configuration runtimeClasspathgo deeper
Just know the two are different: one is about task order, the other about libraries.
Name the tooling for each (dry-run vs. dependencies/dependencyInsight) and what question each answers.
Explain the bridge: project dependencies inject inferred task edges; otherwise the subsystems are independent.
Reason about how resolution strategy and task wiring interact in large multi-project builds and CI graph stability.
## Two graphs, two questions ### 1. Task graph (this topic) - **Nodes**: `Task` instances. - **Edges**: `dependsOn`, inferred output->input wiring, finalizers, ordering rules. - **Question answered**: *What tasks run, and in what order?* - **Tooling**: `gradle <task> --dry-run` prints the ordered plan; cycles raise *Circular dependency between the following tasks*. - **Timing**: resolved at end of configuration, before execution. ### 2. Dependency (artifact) resolution graph - **Nodes**: external/project **components** (modules) and their variants. - **Edges**: declared `dependencies { }` plus transitive metadata. - **Question answered**: *Which versions/artifacts land on this configuration's classpath?* - **Tooling**: `gradle dependencies`, `gradle dependencyInsight --dependency <name>`. - **Mechanics**: version conflict resolution (newest-wins by default), constraints, `resolvable`/`consumable` configurations, capabilities. ## Why people confuse them Both are called 'dependencies' and both are graphs. But one schedules *work* and the other selects *libraries*. A circular *task* dependency is unrelated to a circular *module* dependency (which Gradle handles differently in dependency management). ## Where they touch Resolving a configuration that contains a **project dependency** must produce that project's artifact, so Gradle adds an **inferred task dependency** on the producing task (e.g. `:lib:jar`). That is the bridge: artifact resolution can inject edges into the task graph. But the version-selection logic, conflict resolution, and metadata handling all belong to the artifact subsystem, not to task-graph resolution. ``` Task graph: :compileJava -> :classes -> :jar -> :test Artifact graph: com.example:app -> org.foo:lib:2.1 -> org.bar:core:1.4 \-> org.baz:util:3.0 ```
- Which graph does a 'Circular dependency between the following tasks' error come from?The task graph. It is about Task instances and their ordering, not about module/version resolution.
- How does a project dependency connect the two graphs?Resolving a configuration with a project dependency needs that project's artifact, so Gradle infers a task dependency on the producing task (e.g. :lib:jar), bridging artifact resolution into the task graph.
saying these in an interview costs you the question
- Treating `gradle dependencies` output as the task execution order
- Saying --dry-run shows resolved library versions
- Conflating a circular task dependency with a circular module dependency