After a build, Gradle prints a line like '9 actionable tasks: 2 executed, 5 up-to-date, 2 from cache'. How do you read this summary, and what would it tell you about your build's incrementality?
answer
- actionable = tasks with actions, not lifecycle
- buckets: executed / up-to-date / from cache
- all up-to-date = healthy no-op
- many executed unexpectedly -> --info
- headline; suffixes give detail
basics
~10 sIt counts actionable tasks by outcome: how many actually ran (executed) versus were skipped as up-to-date or restored from cache. Mostly up-to-date/from-cache means a well-behaving incremental build; many executed means real work was redone.
solid answer
~40 sThe summary aggregates the per-task outcomes you saw above it. *Actionable* tasks are those with actions (it excludes pure lifecycle tasks like `build`). The breakdown — `executed`, `up-to-date`, `from cache`, and sometimes `skipped`/`no-source` — is a one-glance health check: - Lots of **up-to-date** → local incremental build working; little changed. - Lots of **from cache** → cache is doing its job, typical of clean/CI builds. - Lots of **executed** when you 'changed nothing' → something is busting up-to-date (use `--info` to find which input/output changed). It's the same data as the suffixes, summarized, and it's a quick way to judge whether your build is reusing work or redoing it.
code
bash · 3 lines$ ./gradlew build
BUILD SUCCESSFUL in 380ms
9 actionable tasks: 2 executed, 5 up-to-date, 2 from cachego deeper
Read the buckets and recognize that all-up-to-date is the fast, healthy case.
Explain 'actionable', and use the summary as the first step before drilling into per-task --info.
Track the executed-count across CI builds to catch incrementality regressions early.
Wire summary/outcome metrics into build observability so caching/incrementality regressions surface across the org.
## Reading the task summary line Every build ends with a one-line tally: ```text 9 actionable tasks: 2 executed, 5 up-to-date, 2 from cache ``` ### What 'actionable' means Gradle distinguishes **actionable** tasks (they have task actions — `compileJava`, `test`, `jar`) from **lifecycle** tasks that only aggregate others (`build`, `check`, `assemble`). The count only tallies actionable ones, because lifecycle tasks don't do work themselves. ### The categories The summary buckets the same outcomes shown per-task: - **executed** — actually ran their actions. - **up-to-date** — skipped, outputs already valid locally. - **from cache** — outputs restored from the build cache. - **skipped** — excluded or `onlyIf` false (shown when present). - **no-source** — empty inputs (shown when present). ### Using it as a health signal | Pattern | Interpretation | |---|---| | Mostly `up-to-date` | Healthy incremental rebuild; expected when you changed little. | | Mostly `from cache` | Fresh/clean/CI build pulling reuse from the cache. | | Many `executed` after a no-op change | Up-to-date is being busted — drill in with `--info`. | | `executed` count grows over time | Possible incrementality regression (an input became unstable). | ### Workflow Treat the summary as the headline, then read the per-task suffixes for detail, and `--info` for the *reason* a task fell into `executed`. On CI, comparing this line across builds is a cheap way to spot when caching/incrementality silently breaks. ```text # Ideal no-op rebuild 7 actionable tasks: 7 up-to-date # Something re-ran unexpectedly 7 actionable tasks: 3 executed, 4 up-to-date <-- why did 3 run? ```
- Why doesn't the count include the `build` task itself?`build` is a lifecycle task with no actions of its own; the summary only tallies actionable tasks that actually do (or skip) work.
- Your no-op rebuild shows '3 executed'. What's your next step?Re-run with --info and read the 'is not up-to-date because' lines for those three tasks to find the changed input or output.
saying these in an interview costs you the question
- Thinking the summary counts every task including lifecycle aggregators.
- Reading a high 'executed' count as automatically bad without checking whether inputs genuinely changed.
- Ignoring the summary as cosmetic — it's a fast incrementality signal.