What does `dependsOn` do in Gradle, and how is a task dependency different from controlling the mere ordering of two tasks?
answer
- dependsOn = add + order
- ordering hooks = order only
- requesting A pulls in its dependsOn
- mustRunAfter no-op if other task absent
- DAG built then executed
basics
~20 sdependsOn declares that one task requires another to run first; if you ask for task A, Gradle also runs its dependencies. A pure ordering hook only sequences tasks that are already scheduled — it never adds a task to the build.
solid answer
~40 s`taskA.dependsOn(taskB)` says: whenever `taskA` is in the task graph, `taskB` must also be in the graph and must complete before `taskA`. Requesting `taskA` therefore *pulls in* `taskB`. This is a true dependency: it both **adds** the dependency to the execution graph and **orders** it. That is fundamentally different from the ordering hooks `mustRunAfter` / `shouldRunAfter`. Those only constrain *relative order* between tasks **that are already going to run** for some other reason; they never cause a task to be scheduled. So `test.mustRunAfter(compile)` does nothing if `compile` isn't already requested. Rule of thumb: reach for `dependsOn` only when A genuinely cannot produce a correct result without B's output; reach for ordering hooks when both run anyway but the sequence matters.
code
kotlin · 8 linesval compile = tasks.register("compileThing")
val pkg = tasks.register("packageThing") {
dependsOn(compile) // pulls compileThing into the graph and orders it first
}
// vs ordering only:
tasks.named("smokeTest") {
mustRunAfter("unitTest") // orders unitTest first ONLY if unitTest is already scheduled
}go deeper
Define dependsOn as 'run this other task first' and know it pulls the task in.
Crisply contrast dependency edges vs pure ordering, and note ordering hooks are no-ops when the other task isn't scheduled.
Explain when to prefer ordering over dependsOn to keep tasks independently runnable, and mention inferred dependencies as the preferred alternative.
Frame as graph-coupling governance: over-using dependsOn bloats graphs and hurts incrementality/parallelism across a large multi-project build.
## The task graph When you run `./gradlew build`, Gradle first builds a **directed acyclic graph (DAG)** of tasks, then executes it. Two distinct things determine that graph: 1. **Which tasks are in it** (the *task selection* / dependency edges). 2. **In what order** the selected tasks run. `dependsOn` affects **both**. `mustRunAfter` / `shouldRunAfter` affect **only ordering** of tasks already selected. ## `dependsOn` ```kotlin val generate = tasks.register("generate") { /* ... */ } tasks.register("package") { dependsOn(generate) // package needs generate's work first } ``` Requesting `package` now guarantees `generate` runs and finishes first. `dependsOn` accepts tasks, task names (Strings), `TaskProvider`s, `Provider`s, `Buildable`s, or even a closure/`Callable` returning any of those, so dependencies can be computed lazily. ## Ordering hooks are NOT dependencies ```kotlin tasks.named("integrationTest") { mustRunAfter("test") // only orders them IF both are scheduled } ``` If you run only `integrationTest`, `test` does **not** run — `mustRunAfter` added no edge that pulls it in. This is the single most common confusion in interviews. ## Why the distinction matters - Over-using `dependsOn` couples tasks and bloats the graph (running `A` drags in `B` even when you didn't want `B`). - Pure ordering needs (e.g. "if both unit and integration tests run, do unit first") should use `mustRunAfter`, not `dependsOn`, so each remains independently runnable. ## Preferred modern style: inferred dependencies In current Gradle you usually should NOT write `dependsOn` by hand at all — wire a *producer task's output Provider* into a consumer's input property and Gradle infers the dependency automatically (covered in the related question). `dependsOn` remains the explicit, coarse-grained escape hatch.
- If I run only `packageThing`, does `compileThing` run?Yes — `dependsOn` pulls it into the graph, so it is scheduled and runs first.
- If I run only `smokeTest`, does `unitTest` run?No. `mustRunAfter` is pure ordering; it never schedules `unitTest`, so nothing pulls it in.
dependsOn is "you can't bake the cake until the oven is preheated — so go preheat it." mustRunAfter is "if you happen to be doing both chores, do the dishes before drying them" — but it never makes you do the dishes.
saying these in an interview costs you the question
- Claiming `mustRunAfter` adds a task to the graph (it does not).
- Saying `dependsOn` only orders tasks — it also selects/pulls them in.