skip to content

Task Selectors and Matching

Invoking tasks by simple name or qualified :project:task path, camelCase abbreviation, excluding tasks, and chaining several in one command. Asked because name-versus-path selection behaves differently in a multi-project build.

on this pageshow

questions

5

When you run `./gradlew test` in a multi-project build, how is that different from running `./gradlew :app:test`? Explain unqualified task names versus fully qualified task paths.

level: juniorimportance: must knowfreq 70%

answer

  1. unqualified = name match across subprojects
  2. qualified `:app:test` = exactly one task
  3. leading colon anchors at root (absolute)
  4. cwd scopes unqualified matching
  5. CI -> qualified paths

basics

~10 s

An unqualified name like test runs the task in every project that has it (within the current project and its subprojects). A qualified path like :app:test targets exactly one project's task.

solid answer

~50 s

A **task selector** can be unqualified (`test`) or fully qualified with a path (`:app:test`). - **Unqualified** (`./gradlew test`): Gradle treats it as a *name match* across the current project **and all its subprojects**. Every project that has a task named `test` is selected, so in a multi-project build you may trigger many `test` tasks at once. - **Qualified** (`./gradlew :app:test`): the leading colon means "from the root," so `:app:test` resolves to exactly one task — the `test` task of the `:app` subproject — and nothing else. Where you invoke from matters for unqualified names: running from a subproject directory scopes the name match to that subproject and its children. Qualified paths are absolute and unaffected by your current directory. Use qualified paths in CI and scripts for deterministic, single-target execution; use unqualified names interactively when you want the aggregate behavior.

code

bash · 8 lines
bash
# Aggregate: every project's `test`
./gradlew test

# Single target, deterministic
./gradlew :app:test

# Nested subproject
./gradlew :services:billing:test

go deeper

for a junior

Know that :app:test targets one project's task and a bare test can hit many.

for a middle

Explain the fan-out semantics and how the current directory scopes unqualified matching.

for a senior

Recommend qualified paths in CI for determinism and discuss task-path uniqueness across the tree.

for a principal

Set org conventions: scripts/CI use qualified paths; reserve aggregate unqualified names for developer ergonomics, and design subproject naming so paths stay readable.

## Task selectors When you type `./gradlew <something>`, each `<something>` that isn't an option flag is a **task selector**. Gradle resolves selectors to a set of concrete task instances and then schedules them (with their dependencies) into the task graph. ## Task paths Every task in a build has a unique **path** built from project paths plus the task name, using `:` as the separator: - `:test` — the `test` task of the **root** project. - `:app:test` — the `test` task of the subproject `:app`. - `:services:billing:test` — nested subproject path. A leading `:` anchors the path at the root, so qualified paths are **absolute** and independent of your working directory. ## Unqualified vs qualified - **Unqualified name** (`test`): Gradle searches the **current project and all of its descendants** for tasks with that name and selects every match. In a build with `:app`, `:lib`, `:web` all owning a `test` task, `./gradlew test` from the root runs all three. - **Qualified path** (`:app:test`): selects exactly the one task at that path. No name-matching fan-out. ## Why the current directory matters for unqualified names Unqualified selection is relative to the **project you invoke from**. From the root, the search covers the whole tree. From inside `app/`, `./gradlew test` only matches `:app` and its children. Qualified paths ignore the current directory entirely. ```bash # From repo root ./gradlew test # runs test in EVERY project that has it ./gradlew :app:test # runs ONLY :app:test, regardless of cwd ``` ## Practical guidance For CI pipelines and automation, prefer **fully qualified paths** so a build does exactly one thing and stays stable as new subprojects are added. Interactively, unqualified names are convenient for "test everything." Note that `help --task :app:test` shows the resolved task's description and type, which is handy when a name is ambiguous.

  • If two subprojects both have a `check` task, what does `./gradlew check` from the root do?
    It selects and runs the `check` task in every project that defines one — root plus all matching subprojects — running them all in one invocation.
  • How can you make an unqualified run target only one subproject without typing the full path?
    `cd` into that subproject's directory and run `./gradlew <task>`; unqualified matching is scoped to the current project and its descendants.

saying these in an interview costs you the question

  • Claiming `./gradlew test` only runs the root project's test task — it fans out across subprojects.
  • Saying qualified paths depend on the current directory — they are absolute from the root.

context

open as a page

What does the `-x` / `--exclude-task` flag do, and how does excluding a task interact with the task dependency graph?

level: middleimportance: must knowfreq 55%

basics

~10 s

-x <task> (or --exclude-task) removes a task from the execution graph for this run. The excluded task and any task that would run only as its dependency are skipped, while requested tasks still run.

open as a page

A developer runs `./gradlew tst` and gets an error; another runs `./gradlew comp` and gets a different error. How does Gradle resolve a task selector, and what are the failure modes for an unmatched or ambiguous name?

level: middleimportance: should knowfreq 35%

basics

~20 s

Gradle tries to match the selector as an exact name, then as a camelCase abbreviation. If nothing matches you get a 'task not found' error (often with did-you-mean suggestions); if the abbreviation matches several tasks you get an 'ambiguous abbreviation' error listing candidates.

open as a page

Explain Gradle's camelCase task-name abbreviation. Why does `./gradlew cT` often resolve to `compileTestJava`, and when does abbreviation fail?

level: middleimportance: should knowfreq 45%

basics

~20 s

Gradle lets you abbreviate a task name by typing the leading letters of each camelCase word. cT expands to a task whose words start c…T…, like compileTest. It fails if the abbreviation matches zero or more than one task.

open as a page

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.

level: seniorimportance: should knowfreq 40%

basics

~20 s

Listing 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.

open as a page