When you run a Gradle build, what does the FROM-CACHE outcome next to a task mean, and how does it differ from UP-TO-DATE and executed?
answer
- FROM-CACHE = unpacked from cache
- UP-TO-DATE = local incremental, unchanged
- executed = ran from scratch
- key = hash of inputs/classpath/type
- needs caching enabled + @CacheableTask
basics
~10 sFROM-CACHE means Gradle restored the task's outputs from the build cache instead of running it. UP-TO-DATE means outputs were already on disk and unchanged. Executed means the task actually ran.
solid answer
~40 sGradle prints an outcome label per task. **Executed** (no label, or shown in `--info`) means the task body ran. **UP-TO-DATE** means incremental build saw the inputs/outputs unchanged on this machine, so it skipped re-running. **FROM-CACHE** means up-to-date checks failed (outputs were missing or stale) but Gradle found a cache entry keyed by the task's inputs and *unpacked* it into the output directory instead of executing. **NO-SOURCE** means the task had no inputs to act on. The key insight: UP-TO-DATE is local incremental state; FROM-CACHE is cross-build/cross-machine reuse via the build cache. Both require the task to be cacheable and the cache enabled (`org.gradle.caching=true`). Seeing FROM-CACHE confirms a cache hit; seeing executed where you expected FROM-CACHE signals a cache *miss* worth diagnosing.
code
bash · 4 lines./gradlew clean build --build-cache --console=verbose
# > Task :compileJava FROM-CACHE
# > Task :processResources UP-TO-DATE
# > Task :test FROM-CACHEgo deeper
Name the three outcomes and that FROM-CACHE means outputs were restored from the cache, not executed.
Distinguish local incremental (UP-TO-DATE) from content-addressed cache reuse (FROM-CACHE) and list the preconditions.
Explain how the cache key drives FROM-CACHE across machines and what it means when an expected hit becomes executed.
Frame outcomes as the observable signal for cache effectiveness across a CI fleet and how outcome ratios feed build-performance governance.
## Task outcomes in Gradle Every task in a Gradle build finishes with an **outcome** that Gradle reports (visibly with `--console=verbose` or in `--info`): - **(no label) / Executed** — the task's actions ran from scratch. - **UP-TO-DATE** — Gradle's *incremental build* (a.k.a. up-to-date checking) determined the task's declared inputs and outputs are unchanged since the last run on this machine, so it skipped execution and kept the existing outputs. - **FROM-CACHE** — up-to-date checking failed (e.g. outputs deleted by `clean`, or you're on a fresh checkout/CI agent), but the **build cache** held an entry whose key matches this task's current inputs, so Gradle *unpacked* the stored outputs into place instead of running the task. - **NO-SOURCE** — the task is up-to-date trivially because it has inputs declared but none are present. - **SKIPPED** — excluded via `onlyIf`, `-x`, or unmet condition. ## Why FROM-CACHE and UP-TO-DATE differ UP-TO-DATE is purely *local* and *temporal*: it compares against the previous build's state on the same machine. The build cache is a *content-addressable store*: each cacheable task computes a **cache key** (a hash of its task type, all declared inputs, the runtime classpath, and the identity of its outputs), and the packed outputs are stored under that key. On a later build — even on a different machine or after `clean` — if the same key is recomputed, Gradle pulls the entry. That's what enables CI agents and teammates to reuse each other's work. ## Preconditions For FROM-CACHE you need: (1) the cache enabled (`org.gradle.caching=true` or `--build-cache`); (2) the task marked cacheable (`@CacheableTask` or `outputs.cacheIf { }`); and (3) a matching entry already in the local or remote cache. If any input changed, the key changes and you get a miss (the task executes and stores a *new* entry). ```bash # Force a cache miss by cleaning, then observe outcomes ./gradlew clean ./gradlew build --build-cache --console=verbose # tasks now print FROM-CACHE where keys matched a prior entry ``` ## Practical reading When a task you *expected* to be FROM-CACHE shows as executed, an input changed the key — that is the start of a cache-miss diagnosis (see `-Dorg.gradle.caching.debug=true`).
- If a task shows UP-TO-DATE, will it ever publish a new cache entry?No. UP-TO-DATE means it didn't run, so there are no fresh outputs to pack; the existing entry (if any) stays. Only executed cacheable tasks store new entries.
- Why might the very first CI build show executed everywhere even with caching on?An empty/cold cache has no entries to match, so every key is a miss; tasks execute and seed the cache for subsequent builds.
UP-TO-DATE is finding last night's leftovers still in your own fridge; FROM-CACHE is grabbing an identical pre-made meal from a shared pantry keyed by its recipe — works even on a kitchen you've never used.
saying these in an interview costs you the question
- Claiming FROM-CACHE and UP-TO-DATE are the same thing
- Thinking UP-TO-DATE tasks repopulate the cache
- Assuming caching works without enabling org.gradle.caching