skip to content

There are two different 'dependency graphs' in Gradle. What is the difference between the task graph and the dependency (artifact) resolution graph?

level: seniorimportance: should knowfreq 35%

answer

  1. task graph = what runs
  2. artifact graph = which jars
  3. dry-run + circular = task graph
  4. dependencies / dependencyInsight = artifact graph
  5. project deps inject inferred task edges

basics

~20 s

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

Gradle 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
bash
# Task graph (this topic)
gradle test --dry-run

# Artifact / dependency-management graph (different subsystem)
gradle dependencies --configuration runtimeClasspath
gradle dependencyInsight --dependency slf4j-api --configuration runtimeClasspath

go deeper

for a junior

Just know the two are different: one is about task order, the other about libraries.

for a middle

Name the tooling for each (dry-run vs. dependencies/dependencyInsight) and what question each answers.

for a senior

Explain the bridge: project dependencies inject inferred task edges; otherwise the subsystems are independent.

for a principal

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

context