What does task.onlyIf {} do in Gradle, and what happens to a task whose onlyIf predicate returns false?
answer
- predicate at execution time
- false → SKIPPED outcome
- actions not run
- multiple onlyIf = AND
- reason-string overload (7.6+)
basics
~10 sonlyIf {} attaches a predicate evaluated right before the task runs. If it returns false, Gradle skips the task's actions and reports it as SKIPPED. If true (or absent), the task executes normally.
solid answer
~40 s`onlyIf {}` registers a spec/predicate that Gradle evaluates at **execution time**, just before running the task's actions. If the predicate returns `false`, the task's `doFirst`/`doLast` actions are NOT run and the build reports the task outcome as `SKIPPED`. If it returns `true` (or no `onlyIf` is set), the task proceeds to its normal up-to-date check and may then run or be `UP-TO-DATE`. It receives the task as an argument, so you can branch on task state. Multiple `onlyIf {}` calls are ANDed together — the task runs only if every predicate is true. It's the right tool for 'skip this task under some runtime condition' (e.g. a property/flag/file presence) without removing the task from the graph or failing the build.
code
kotlin · 7 linestasks.register("deploy") {
onlyIf("deploy only on the release branch") {
System.getenv("BRANCH") == "release"
}
doLast { println("deploying") }
}
// Not on release branch → > Task :deploy SKIPPEDgo deeper
Know that onlyIf is a true/false guard run before the task, and false yields a SKIPPED task.
Explain execution-time evaluation, the ANDing of multiple predicates, and the SKIPPED outcome vs other outcomes.
Contrast onlyIf with up-to-date checks and configuration-time conditionals; mention the reason-string overload and lazy-config implications.
Frame onlyIf as one of several gating mechanisms and advise when a predicate vs configuration-time exclusion vs task-graph filtering is the right lever for build maintainability.
## What `onlyIf` is Every Gradle `Task` exposes `onlyIf(Spec<? super Task>)` (and Kotlin/Groovy closure overloads). The spec is a **predicate** that returns a boolean. Gradle evaluates it during the **execution phase**, immediately before it would run the task's actions. - Predicate `true` (or no `onlyIf` set) → Gradle continues to the task's up-to-date check, then runs the actions if needed. - Predicate `false` → Gradle does **not** run any of the task's actions and prints the outcome as `SKIPPED`. ## Why it matters It lets you conditionally disable a task at runtime without deleting it from the task graph, without an early `return`, and without throwing. Common uses: skip publishing unless a flag is set, skip a step when an input directory is empty, skip slow checks on a developer machine. ## ANDing and the task argument Calling `onlyIf` more than once **adds** predicates; the task runs only if **all** of them return true (logical AND). Each predicate receives the task itself, so you can inspect task state. Gradle 7.6+ added an overload taking an explanatory reason string, which shows up in `--info`/`--debug` logs explaining *why* a task was skipped. ## Execution-time vs configuration-time The predicate body runs during execution, not configuration. So referencing values that are only known after configuration (e.g. another task's output, a resolved property) is safe inside `onlyIf {}`. Contrast with an `if (...) { tasks.register(...) }` block, which decides at configuration time whether the task even exists. ```kotlin tasks.register("publishDocs") { onlyIf("only publish when -PreleaseDocs is set") { project.hasProperty("releaseDocs") } doLast { println("publishing...") } } ``` If you run without `-PreleaseDocs`, the console shows `> Task :publishDocs SKIPPED`.
- If you call onlyIf twice on the same task, when does the task run?Only when both predicates return true — additional onlyIf calls are ANDed together.
- What console outcome label does a task get when its onlyIf returns false?SKIPPED.
saying these in an interview costs you the question
- Saying a false onlyIf makes the build FAIL — it skips, not fails.
- Claiming the predicate runs at configuration time — it runs at execution time.