skip to content

Conditional Execution: onlyIf

The onlyIf predicate that skips a task at execution time and reports it as SKIPPED. Interviewers ask how it differs from an up-to-date check and from a plain if statement in the configuration phase.

on this pageshow

questions

5

What does task.onlyIf {} do in Gradle, and what happens to a task whose onlyIf predicate returns false?

level: juniorimportance: must knowfreq 70%

answer

  1. predicate at execution time
  2. false → SKIPPED outcome
  3. actions not run
  4. multiple onlyIf = AND
  5. reason-string overload (7.6+)

basics

~10 s

onlyIf {} 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 lines
kotlin
tasks.register("deploy") {
    onlyIf("deploy only on the release branch") {
        System.getenv("BRANCH") == "release"
    }
    doLast { println("deploying") }
}
// Not on release branch → > Task :deploy SKIPPED

go deeper

for a junior

Know that onlyIf is a true/false guard run before the task, and false yields a SKIPPED task.

for a middle

Explain execution-time evaluation, the ANDing of multiple predicates, and the SKIPPED outcome vs other outcomes.

for a senior

Contrast onlyIf with up-to-date checks and configuration-time conditionals; mention the reason-string overload and lazy-config implications.

for a principal

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.

context

open as a page

How does onlyIf differing from an up-to-date check (outputs.upToDateWhen)? When would you reach for each?

level: middleimportance: must knowfreq 60%

basics

~20 s

onlyIf decides whether the task should run at all (false → SKIPPED). The up-to-date check decides whether work is unnecessary because inputs/outputs are unchanged (→ UP-TO-DATE). onlyIf runs first; if it passes, Gradle then does the up-to-date check.

open as a page

What is the difference between gating a task with onlyIf {} versus a configuration-time if-block that conditionally registers or wires the task?

level: middleimportance: should knowfreq 45%

basics

~20 s

A configuration-time if-block decides whether the task is even created/wired while scripts are evaluated. onlyIf decides at execution time whether an existing task runs. Configuration-time conditions can use only configuration-known values; onlyIf can use values known later.

open as a page

What are common pitfalls when writing onlyIf predicates, particularly around side effects, exceptions, and lazy configuration?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Keep onlyIf predicates pure and cheap: no mutating state, no heavy I/O, and don't throw (an exception there fails the build, not a clean skip). Read inputs lazily via Providers, and don't rely on configuration order since the body runs at execution.

open as a page

When you call onlyIf multiple times on a task, how are the predicates combined, and how can you make a skip reason visible in the logs?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Multiple onlyIf predicates are ANDed: the task runs only if all return true. To surface why it skipped, use the onlyIf(reason) { } overload (Gradle 7.6+); the reason appears in --info/--debug output when the task is skipped.

open as a page