What's the difference between mustRunAfter and dependsOn in Gradle?

Solution 1:

For example:

tasks.create('a')

tasks.create('b').dependsOn('a')

tasks.create('c')

tasks.create('d').mustRunAfter('c')
  • dependsOn - sets task dependencies. Executing b here would require that a be executed first.
  • mustRunAfter - sets task ordering. Executing d does not require c. But, when both c and d are included, c will execute before d.

Solution 2:

Sometimes they have the same effect. For example, if taskC dependsOn taskA and taskB, then it doesn't matter whether taskB dependsOn taskA or mustRunAfter it - when you run taskC, the order will be taskA, taskB, taskC.

But if taskC dependsOn taskB only, then there's a difference. If taskB dependsOn taskA, then it's the same as above - taskA, taskB, taskC. If taskB merely mustRunAfter taskA, then taskA doesn't run, and running taskC will run taskB, then taskC.

mustRunAfter really means if taskA runs at all, then taskB must run after it.

Solution 3:

Where possible, declare task inputs instead of task dependencies. That said, expanding on mkobit's answer:

Ordering and dependencies involving two tasks

mustRunAfter

mustRunAfter controls the execution order of tasks explicitly specified on the command line, but doesn't create implicit dependencies on other tasks. Given taskA and taskB:

build.gradle.kts

val taskA by tasks.registering {
    doLast {
        println("taskA")
    }
}

val taskB by tasks.registering {
    doLast {
        println("taskB")
    }
}

taskB {
    mustRunAfter(taskA)
}

then

  • gradle taskB taskA executes taskA followed by taskB;
  • gradle taskA executes taskA only;
  • gradle taskB executes taskB only.

dependsOn

dependsOn creates implicit dependencies on other tasks. Given the same two tasks:

taskB {
    dependsOn(taskA)
}

then

  • gradle taskB executes taskA followed by taskB;
  • gradle taskB taskA executes taskA followed by taskB;
  • gradle taskA executes taskA only.

Ordering and dependencies involving three tasks

mustRunAfter and dependsOn accept an unordered collection of tasks. Given:

val taskC by tasks.registering {
    doLast {
        println("taskC")
    }
}

taskC {
    dependsOn(taskA, taskB)
}

then gradle taskC executes taskA and taskB in no guaranteed order, followed by taskC (assuming no other dependsOn or mustRunAfter declarations).

mustRunAfter also controls the execution order between interdependent tasks that would otherwise have no guaranteed order. Given:

taskB {
    mustRunAfter(taskA)
}

then gradle taskC executes taskA followed by taskB followed by taskC, but gradle taskB only runs taskA because taskB does not dependOn(taskA).

Other types of task dependency

  • taskA { finalizedBy(taskB) } ensures gradle taskA executes taskA followed by taskB;
  • shouldRunAfter provides weaker ordering guarantees than mustRunAfter, useful for breaking cyclic dependencies and parallel task execution.

Further reading

Consult the Gradle documentation for more information on:

  • adding dependencies to tasks
  • ordering tasks
  • skipping tasks