What is an ad-hoc task in Gradle, and how do you define one?
answer
- DefaultTask base class
- doLast / doFirst actions
- execution vs configuration phase
- tasks.register lazy
- group / description / dependsOn
basics
~10 sAn ad-hoc task is an untyped task of type DefaultTask whose behavior you add inline with doLast { ... }. You register it with tasks.register("name") and put the action in the closure.
solid answer
~40 sAn **ad-hoc task** is a task you define without a custom or built-in task type — it is backed by `DefaultTask`, the base class every task extends. Instead of getting behavior from a class, you attach actions inline using `doLast { ... }` (or `doFirst { ... }`). Example: `tasks.register("hello") { doLast { println("hi") } }`. The `doLast` block runs during the execution phase when the task is actually invoked, not during configuration. Ad-hoc tasks are ideal for quick, one-off, project-specific glue logic where writing a reusable task class would be overkill. You still set common properties like `group`, `description`, and `dependsOn` on them. The trade-off is that the logic isn't reusable, isn't independently testable, and (because it usually captures arbitrary closures) is harder to make cacheable or incremental than a properly typed task.
code
kotlin · 7 linestasks.register("greet") {
group = "custom"
description = "Prints a greeting"
doLast {
println("Hello from Gradle")
}
}go deeper
Know that an ad-hoc task uses doLast and is registered with tasks.register; name DefaultTask as the base.
Explain the configuration-vs-execution phase distinction and why work belongs in doLast; set group/description/dependsOn.
Discuss when to promote an ad-hoc task to a typed/custom task for reuse, testability, and up-to-date checks.
Frame ad-hoc tasks as a code-smell at scale: they evade input/output tracking and caching; set conventions to keep build logic in plugins/typed tasks.
## What "ad-hoc" means Every Gradle task is an instance of a class. When you use a **typed** task you pick a class that already has behavior — e.g. `Copy`, `Zip`, `Exec`, `Delete`, or your own custom `DefaultTask` subclass. An **ad-hoc task** skips writing a class: Gradle gives you a plain instance of `DefaultTask` (the abstract base class for all tasks) and you bolt behavior onto it inline. ## How behavior attaches: actions A task's work is a list of **actions**. You append actions with two methods: - `doFirst { ... }` — adds an action to the **front** of the action list. - `doLast { ... }` — adds an action to the **end** of the action list. These run in the **execution phase**, only if and when the task actually runs. Code written directly in the configuration block (outside `doFirst`/`doLast`) runs in the **configuration phase**, every build, whether or not the task executes — a common source of bugs. ## Registering an ad-hoc task ```kotlin tasks.register("greet") { group = "custom" description = "Prints a greeting" doLast { println("Hello from Gradle") } } ``` `tasks.register(...)` returns a `TaskProvider<Task>` and uses the **configuration-avoidance API** — the configuration block runs lazily, only if the task is needed. The older `tasks.create(...)` is eager and configures immediately. ## Common properties on ad-hoc tasks - `group` — the category shown under `gradle tasks` (e.g. "build", "verification"). - `description` — the one-line help text shown next to the task. - `dependsOn(...)` — declares that other tasks must run first. ## Typed vs ad-hoc | | Ad-hoc (`DefaultTask` + `doLast`) | Typed (`Copy`, custom class) | |---|---|---| | Behavior | Inline closures | From the class | | Reuse | None | Reusable across builds | | Inputs/outputs | Must wire manually | Often declared on the type | | Caching/incremental | Hard | Designed in | Use ad-hoc tasks for small, local glue; promote to a typed/custom task once logic grows, repeats, or needs up-to-date checks.
- Where does code outside doLast/doFirst run?In the configuration phase — every build, regardless of whether the task executes. Only doFirst/doLast bodies run in the execution phase.
- What is the supertype of an ad-hoc task?DefaultTask — the abstract base class all Gradle tasks extend; ad-hoc tasks are plain DefaultTask instances with inline actions.
saying these in an interview costs you the question
- Putting real work (file IO, println of computed state) outside doLast, so it runs every configuration
- Claiming ad-hoc tasks have no type — they are DefaultTask instances