skip to content

What is the difference between the tasks a user requested on the command line and the tasks Gradle actually schedules and executes?

level: juniorimportance: must knowfreq 55%

answer

  1. startParameter.taskNames = requested
  2. taskGraph.allTasks = scheduled
  3. config phase builds the DAG
  4. scheduled != actions ran (UP-TO-DATE still scheduled)
  5. --dry-run previews the set

basics

~10 s

Requested tasks are the names you type on the command line (e.g. gradle build). Executed tasks are those plus all their dependencies, which Gradle computes and runs in dependency order.

solid answer

~30 s

When you run `gradle build`, `build` is the *requested* task — the entry point you asked for. Before running anything, Gradle's configuration phase resolves the full set of tasks needed: the requested tasks plus everything they depend on (transitively), producing the *executed* set ordered as a directed acyclic graph. So `build` typically pulls in `compileJava`, `test`, `jar`, and more. The requested names live in `gradle.startParameter.taskNames`; the scheduled set is `gradle.taskGraph.allTasks`. Tasks already `UP-TO-DATE` or `FROM-CACHE` are still *scheduled* (in the graph) even if their actions are skipped — scheduled is not the same as 'actions ran'.

code

bash · 10 lines
bash
$ gradle build --dry-run
:compileJava SKIPPED
:processResources SKIPPED
:classes SKIPPED
:jar SKIPPED
:assemble SKIPPED
:compileTestJava SKIPPED
:test SKIPPED
:check SKIPPED
:build SKIPPED

go deeper

for a junior

Know that typing gradle build runs build plus its dependencies, and that --dry-run shows the list.

for a middle

Name the two APIs (startParameter.taskNames vs taskGraph.allTasks) and explain the configuration phase builds the DAG.

for a senior

Distinguish scheduled from actions-executed (UP-TO-DATE/FROM-CACHE still scheduled) and explain why hasTask beats string matching.

for a principal

Frame the requested→scheduled resolution as a build-correctness contract; reason about how task selectors, abbreviations, and multi-project paths affect the closure across a large build.

## Two distinct concepts Gradle runs in three phases: **initialization**, **configuration**, and **execution**. Understanding 'requested vs executed' means understanding what each phase produces. ### Requested tasks The *requested* tasks are exactly the task names (and selectors) you passed on the command line. They are available as `gradle.startParameter.taskNames`, a `List<String>` of the raw strings, e.g. `["clean", "build"]`. These are the user's *intent* — the entry points. ### The task graph (scheduled / executed tasks) During configuration, Gradle builds a **task execution graph** — a Directed Acyclic Graph (DAG) where nodes are task instances and edges are dependencies declared via `dependsOn`, inputs/outputs wiring, `mustRunAfter`, `shouldRunAfter`, and `finalizedBy`. For each requested task, Gradle walks its dependency closure and adds every required task. The resulting ordered set is exposed as `gradle.taskGraph.allTasks` (a `List<Task>`). So `gradle build` might request just `build`, but the graph contains `compileJava`, `processResources`, `classes`, `compileTestJava`, `test`, `jar`, `assemble`, `check`, and `build` — all of them *scheduled*. ### Scheduled vs 'actions actually ran' A scheduled task still appears in the graph even when its actions are skipped at execution time because it is `UP-TO-DATE`, `FROM-CACHE`, `NO-SOURCE`, or `SKIPPED` (via `onlyIf`). 'Scheduled' means 'will be visited during execution'; whether its `doFirst`/`doLast` actions actually fire is decided per-task at execution time. ### Why it matters Plugins and build logic often need to react *only when* a particular task is in the play — for example, configuring something expensive only if `test` will run. The wrong way is to check `startParameter.taskNames` (a string match that misses tasks pulled in transitively or by abbreviation). The right way is `gradle.taskGraph.hasTask(":module:test")` after the graph is ready. ```kotlin gradle.taskGraph.whenReady { val requested = gradle.startParameter.taskNames // e.g. ["build"] val scheduled = allTasks.map { it.path } // [":compileJava", ":test", ":jar", ...] if (hasTask(":test")) { logger.lifecycle("test is scheduled — enabling extra reporting") } } ``` ### --dry-run To *preview* the executed set without running it, use `gradle build --dry-run` (or `-m`). Gradle prints each task it *would* run with a `SKIPPED` marker and performs no actions — the clearest way to see the gap between what you requested and what actually gets scheduled.

  • If a task shows UP-TO-DATE, was it scheduled?
    Yes. UP-TO-DATE means it was in the graph and visited, but its actions were skipped because inputs/outputs were unchanged. Scheduled and 'actions executed' are different.
  • How do you see the executed set without running anything?
    Run with `--dry-run` (`-m`). Gradle resolves the graph and prints each task it would run, marked SKIPPED, executing no actions.

Requested tasks are the destination you type into a GPS; the executed set is the full turn-by-turn route the GPS computes to get you there.

saying these in an interview costs you the question

  • Saying requested and executed are the same thing.
  • Claiming UP-TO-DATE tasks are not part of the task graph.
  • Confusing 'task is scheduled' with 'task's actions ran'.

context