What does it mean when Gradle marks a task as UP-TO-DATE, and how does Gradle decide that?
answer
- input/output snapshots compared
- task history under .gradle
- UP-TO-DATE = skip action
- outputs checked too
- local, not the build cache
basics
~10 sUP-TO-DATE means Gradle skipped the task because its inputs and outputs haven't changed since the last run. Gradle compares snapshots of the declared inputs/outputs; if they match, it reuses the previous result.
solid answer
~40 sWhen a task runs, Gradle takes a fingerprint (snapshot) of everything declared as an input (`@Input` values, `@InputFile`/`@InputFiles` contents) and everything declared as an output (`@OutputFile`/`@OutputDirectory`). It stores these in the build's task history. On the next run, before executing the task, Gradle re-snapshots the inputs and outputs and compares them. If nothing changed — same input values, same input file hashes, output files still present and unmodified — Gradle skips the task action entirely and prints `UP-TO-DATE` next to the task in the console. This is the core of Gradle's incremental build: only tasks whose inputs or outputs actually changed re-execute. It is purely local (per-project build history) and is distinct from the build cache, which can reuse outputs across machines.
code
bash · 5 lines$ ./gradlew compileJava
> Task :compileJava
$ ./gradlew compileJava --console=verbose
> Task :compileJava UP-TO-DATE # nothing changed, action skippedgo deeper
Recall that UP-TO-DATE means the task was skipped because inputs/outputs didn't change.
Explain the snapshot-and-compare cycle and that file contents are hashed, plus that outputs are checked too.
Contrast up-to-date checking (local incremental) with the build cache, and note that undeclared inputs are invisible.
Frame up-to-date correctness as a contract: task authors must declare every input/output or risk stale builds; tie into reproducibility and cache hit-rate strategy across the org.
## What "UP-TO-DATE" means Gradle is a task graph executor. For each task it tries to avoid doing work that has already been done. The mechanism is **up-to-date checking**: a task is *up to date* when its declared inputs and outputs are byte-for-byte equivalent to the last time the task executed successfully. ## How Gradle knows the inputs and outputs A task declares its inputs and outputs through annotations on its properties: - `@Input` — a scalar value (String, Int, enum, etc.). - `@InputFile` / `@InputFiles` / `@InputDirectory` — file inputs whose *contents* are fingerprinted (hashed), not just their paths. - `@OutputFile` / `@OutputDirectory` / `@OutputFiles` — the files the task produces. Gradle only tracks what is declared. A value the task reads but does not declare is invisible to up-to-date checking, which is a common source of stale builds. ## The snapshot/fingerprint cycle 1. **Before execution**, Gradle computes a fingerprint of all inputs (hashing file contents, capturing input-property values) and records the set of output locations. 2. It compares this to the **task history** stored under `.gradle/` from the previous run. 3. If the input fingerprints match **and** the outputs are still present and unmodified, the task is skipped and reported as `UP-TO-DATE`. 4. If anything differs, the task executes; afterward Gradle snapshots the new outputs and stores fresh history. Outputs are checked too: if you delete or hand-edit an output file, the task is no longer up to date and re-runs. ## Seeing it in the console Run with `--console=verbose` (or read the build scan) to see the outcome label after each task: ``` > Task :compileJava UP-TO-DATE > Task :processResources NO-SOURCE > Task :jar ``` Labels include `UP-TO-DATE` (skipped, inputs unchanged), `NO-SOURCE` (no input files at all), `FROM-CACHE` (restored from the build cache), and no label (executed). ## Relationship to other features Up-to-date checking is **local and incremental** — it answers "did anything change since *my* last build?". The **build cache** is a superset that can reuse outputs produced by a *different* build or machine keyed by the same input fingerprint. A task that is cacheable still goes through up-to-date checking first; the cache is only consulted when the task is out of date.
- If you edit an output file by hand and re-run, what happens?The output snapshot no longer matches the recorded history, so the task is out of date and re-executes, regenerating the output.
- Is UP-TO-DATE the same as FROM-CACHE?No. UP-TO-DATE means the local outputs from the previous run are reused. FROM-CACHE means outputs were restored from the (possibly remote) build cache for a task that was out of date locally.
Like a build-it-yourself recipe with a checklist: if every ingredient and the finished dish are exactly as you left them, you don't cook again — you just serve what's already plated.
saying these in an interview costs you the question
- Saying Gradle compares timestamps like Make — it fingerprints content (hashes), not mtimes.
- Claiming UP-TO-DATE and the build cache are the same mechanism.