When you run `./gradlew clean build` versus `./gradlew build clean`, does the order of the task arguments matter? Explain how Gradle orders multiple requested tasks.
answer
- all args -> one DAG
- deps + mustRunAfter/shouldRunAfter dominate
- CLI order = tie-break only
- clean & build have no hard edge
- each task runs at most once
basics
~20 sListing multiple tasks requests them all in one run. Command-line order is honored only as a tie-break; real ordering comes from task dependencies and mustRunAfter/shouldRunAfter. clean build and build clean can both work because clean and build have no hard dependency between them, but the requested order biases scheduling.
solid answer
~50 sPassing several selectors (`./gradlew clean build`) schedules **all** of them plus their dependencies into one graph. Gradle does **not** simply run them left-to-right; the executor topologically sorts by: 1. **Hard dependencies** (`dependsOn`, producer/consumer relationships) — always honored. 2. **Ordering rules** (`mustRunAfter`, `shouldRunAfter`) declared in the build. 3. **Command-line order** as a soft tie-break when nothing else constrains two tasks. So `clean build` and `build clean` usually produce the same effective schedule because `build` does not depend on `clean`; Gradle uses the requested order only to break ties. The well-known gotcha: people assume `build clean` runs build then deletes the output — but if `clean` is unordered relative to producers, you can get surprising results. That's why Gradle plugins often declare `clean.mustRunAfter`/`shouldRunAfter` or rely on lifecycle wiring. In practice, `clean build` is the canonical "wipe then build" incantation precisely because the requested order tie-breaks `clean` before `build`'s producers when otherwise unconstrained.
code
bash · 2 lines./gradlew clean build # idiomatic from-scratch build
./gradlew clean test :app:run # one graph: clean, then test, then rungo deeper
Know you can list several tasks in one command and clean build is the common rebuild form.
Explain that order is mostly from dependencies and CLI order is just a tie-break.
Distinguish dependsOn vs mustRunAfter/shouldRunAfter and explain why clean/build ordering works as it does.
Guide teams to encode ordering via wiring/ordering rules rather than relying on CLI argument order, and to design tasks so outputs feed inputs for implicit correct ordering.
## Multiple selectors = one graph Every non-flag argument is a requested task. `./gradlew clean build test` asks Gradle to make **clean, build, and test** all happen in a single execution. Gradle collects their transitive dependencies and produces one **directed acyclic graph (DAG)**, then schedules it. ## What determines execution order Order is **not** purely the order you typed. Gradle's executor sorts tasks using, in priority: 1. **Dependency edges** — `dependsOn`, plus implicit edges from one task consuming another's output (the modern wiring via `Provider`/`TaskProvider` inputs). These are *hard* and never violated. 2. **Ordering constraints** — `task.mustRunAfter(other)` (a hard ordering edge that doesn't add a dependency) and `task.shouldRunAfter(other)` (a soft preference Gradle drops if it would create a cycle or hurt parallelism). 3. **Command-line order** — used only to break ties between tasks that are otherwise unordered. ```kotlin // In a build script: ensure clean precedes a packaging task without // making clean a dependency (so packaging can run alone too). tasks.named("distZip") { mustRunAfter("clean") } ``` ## `clean build` vs `build clean` `clean` (from the base plugin) deletes the `build/` directory. `build` aggregates `assemble` + `check`. There is **no dependency** between them. Therefore: - `./gradlew clean build`: tie-break puts `clean` first, then build's producers run and regenerate outputs. This is the idiomatic "from-scratch build." - `./gradlew build clean`: the tie-break biases `clean` later, which can mean you build and then delete outputs — rarely what you want. Because there's no hard ordering, results can be confusing, which is exactly why `clean build` is the convention. ## Key principle for interviews Never describe multi-task invocation as "runs them in the order typed." State that Gradle builds a graph and that **dependencies and ordering rules dominate; CLI order is only a tie-break**. Each requested task and its dependencies execute **at most once** even if reachable multiple ways.
- If `build` does not depend on `clean`, why does `clean build` reliably wipe then rebuild?Because with no hard ordering between them, Gradle uses the command-line order as a tie-break, scheduling `clean` before `build`'s producer tasks.
- How would you force `clean` to run before a packaging task without making it a dependency?Declare `packagingTask.mustRunAfter(clean)` (or `shouldRunAfter` for a soft preference). This adds an ordering edge without adding a dependency.
- If a task is reachable through two requested tasks, how many times does it run?Once. Gradle deduplicates tasks in the graph, so each task executes at most once per build.
saying these in an interview costs you the question
- Stating Gradle runs requested tasks strictly in the order typed.
- Confusing `mustRunAfter` (ordering only) with `dependsOn` (ordering + requirement).