skip to content

What is @DisableCachingByDefault and how does disabling caching relate to forcing a task to rerun?

level: seniorimportance: should knowfreq 30%

answer

  1. task-class annotation, org.gradle.work
  2. opposite of @CacheableTask
  3. removes FROM-CACHE path only
  4. still needs upToDateWhen{false} to force rerun
  5. because = documents rationale

basics

~20 s

@DisableCachingByDefault marks a task type as not cached by the build cache by default, so its outputs are never restored FROM-CACHE. That removes one path that could skip real work, but it does NOT disable up-to-date checking.

solid answer

~50 s

`@DisableCachingByDefault` is a task-class annotation (from `org.gradle.work`) declaring that instances of that task type are **not** build-cacheable unless explicitly opted back in. Many Gradle built-in tasks carry it because caching them is unsafe or pointless (e.g. they're too cheap, or outputs aren't relocatable). It matters to 'forcing rerun' because there are *two* ways Gradle can avoid running a task: it's `UP-TO-DATE` (inputs/outputs unchanged) or it's served `FROM-CACHE`. Disabling caching only removes the second path. So to truly guarantee a task does its work you must address **both**: defeat up-to-date (e.g. `outputs.upToDateWhen { false }` or `--rerun`) *and* ensure it isn't cache-restored (`@DisableCachingByDefault` on the type, or `outputs.cacheIf { false }` per-task, or `--no-build-cache` for the run). It's a good idea to put `@DisableCachingByDefault(because = "...")` on custom task types whose outputs depend on non-cacheable external state.

code

kotlin · 9 lines
kotlin
import org.gradle.work.DisableCachingByDefault

@DisableCachingByDefault(because = "Outputs depend on live external state; not reproducible")
abstract class SyncRemoteTask : DefaultTask() {
    init {
        // annotation kills FROM-CACHE; this kills UP-TO-DATE -> always runs
        outputs.upToDateWhen { false }
    }
}

go deeper

for a junior

Recognize it marks a task type as not build-cached by default.

for a middle

Separate the two skip paths (UP-TO-DATE vs FROM-CACHE) and know the annotation only kills the cache path.

for a senior

Combine the annotation with outputs.upToDateWhen{false} for guaranteed execution; contrast with cacheIf{false} and --no-build-cache; justify by non-reproducible outputs.

for a principal

Set conventions for annotating non-deterministic task types with a documented because, improving cacheability reports and avoiding unsafe remote-cache poisoning across the org.

## Two independent skip mechanisms Gradle can decline to execute a task's actions for two distinct reasons: 1. **Up-to-date** — declared inputs and outputs are unchanged since last run (`UP-TO-DATE`). 2. **Build cache** — for a cacheable task, a matching entry (keyed by hashed inputs) exists in the local or remote cache, so outputs are unpacked instead of recomputed (`FROM-CACHE`). Forcing a rerun means defeating **whichever of these applies**. The CLI `--rerun`/`--rerun-tasks` defeat both for an invocation. Programmatic controls each target one mechanism. ## The annotation `@DisableCachingByDefault` lives in package `org.gradle.work` and is applied to a **task class**: ```kotlin import org.gradle.work.DisableCachingByDefault @DisableCachingByDefault(because = "Talks to a live endpoint; outputs aren't reproducible") abstract class DeployTask : DefaultTask() { /* ... */ } ``` It means: instances of this type are **not** stored in or restored from the build cache by default. The `because` string documents the rationale and shows in build-scan/cacheability reports. A task type is opted *into* caching with `@CacheableTask`; `@DisableCachingByDefault` is the explicit opposite (and is also Gradle's default for task types that declare neither — the annotation makes the intent and reason explicit and suppresses cacheability warnings). ## How it relates to rerun Disabling caching alone does **not** force rerun — a non-cacheable task can still be `UP-TO-DATE` and skipped. Conversely, `outputs.upToDateWhen { false }` defeats up-to-date but a `@CacheableTask` could still be served `FROM-CACHE`. The robust recipe to guarantee real execution every time: ```kotlin @DisableCachingByDefault(because = "non-reproducible outputs") abstract class AlwaysRunTask : DefaultTask() { init { outputs.upToDateWhen { false } // defeat up-to-date // caching already off via the annotation } } ``` ## Per-invocation alternatives - `--no-build-cache` disables the cache for the whole run (removes FROM-CACHE but not UP-TO-DATE). - `outputs.cacheIf { false }` disables caching for one task instance. - `--rerun` / `--rerun-tasks` defeat both up-to-date and cache for the invocation. ## When to use the annotation Put `@DisableCachingByDefault(because = ...)` on custom task types whose outputs are non-deterministic, environment-specific, or not relocatable — it's safer and clearer than relying on callers to remember `--no-build-cache`, and the `because` documents *why* for future maintainers and cacheability reports.

  • Does @DisableCachingByDefault by itself force a task to rerun every build?
    No. It only prevents cache restore (FROM-CACHE). The task can still be UP-TO-DATE and skipped. To force rerun you also defeat up-to-date checking.
  • What's the difference between @DisableCachingByDefault and outputs.cacheIf { false }?
    The annotation declares non-cacheability at the task-type level (with a documented reason); cacheIf { false } disables caching for a single task instance at configuration time. Both stop FROM-CACHE.
  • How does --no-build-cache compare?
    It disables the build cache for the entire invocation (no FROM-CACHE for any task) but leaves up-to-date checking intact, so unchanged tasks are still skipped as UP-TO-DATE.

saying these in an interview costs you the question

  • Claiming @DisableCachingByDefault forces re-execution on its own.
  • Confusing disabling caching with disabling up-to-date checking — they're separate mechanisms.
  • Forgetting the required because rationale / its value in cacheability reports.

context