skip to content

Dry Run And Task Timing Flags

Previewing the planned task graph with --dry-run and surfacing per-phase and per-task timings. A quick practical question about how you inspect a build before committing to running it.

on this pageshow

questions

5

What does the --dry-run flag do when you run a Gradle build, and when would you use it?

level: juniorimportance: must knowfreq 60%

answer

  1. prints task graph, executes nothing
  2. alias -m
  3. tasks shown as SKIPPED in real order
  4. configuration still runs, actions don't
  5. preview before slow/destructive goal

basics

~10 s

--dry-run makes Gradle print the ordered list of tasks it WOULD run for your requested goal, without actually executing any of them. It's a safe way to preview the task graph.

solid answer

~30 s

`--dry-run` (alias `-m`) runs Gradle's configuration phase normally, builds the full task execution graph for the requested tasks, then prints each task in execution order with a `SKIPPED` marker instead of executing it. No task actions, no outputs, no side effects. It's useful to (1) verify which tasks a goal like `build` actually pulls in via `dependsOn`/`finalizedBy`, (2) confirm task ordering before a destructive or slow operation, and (3) sanity-check a wiring change without paying execution cost. Note it still *configures* the build, so configuration-time logic and any `doFirst`/`doLast` are NOT triggered, but plugin configuration and lazy task registration still happen.

code

bash · 4 lines
bash
# Preview what 'build' actually runs, without executing anything
./gradlew build --dry-run
# Short alias
./gradlew build -m

go deeper

for a junior

Know it previews the ordered task list without executing, and shows tasks as SKIPPED.

for a middle

Explain the phase model: configuration still runs, only execution is replaced; name the alias -m.

for a senior

Discuss precise semantics — what is and isn't triggered — and practical uses (auditing wiring, previewing destructive goals).

for a principal

Position it within a measurement toolkit: --dry-run for graph shape, separate tools for timing/cache; caution that it won't catch slow or side-effecting configuration.

## What a Gradle build does in phases Every Gradle invocation runs three phases: 1. **Initialization** — decides which projects participate (reads `settings.gradle(.kts)`). 2. **Configuration** — evaluates every build script needed, registers/configures tasks, and builds the **task graph** (a directed acyclic graph of task dependencies from `dependsOn`, `mustRunAfter`, `finalizedBy`, and input/output wiring). 3. **Execution** — runs the selected tasks' actions in dependency order. ## What --dry-run changes `--dry-run` (short form `-m`) runs **initialization and configuration normally** but **replaces execution with a print-out**. For each task that *would* run, Gradle prints the task path followed by `SKIPPED`: ``` :compileJava SKIPPED :processResources SKIPPED :classes SKIPPED :jar SKIPPED :assemble SKIPPED ``` The order shown is the real planned execution order, so it's an accurate preview of the task graph for the requested goal. ## What it does and does NOT trigger - **Triggered:** project evaluation, plugin application, task *registration* and *configuration* closures, and graph construction. Anything in a configuration block (e.g. `tasks.register("x") { ... }`) runs. - **NOT triggered:** the task *actions* themselves — `doFirst`, `doLast`, `@TaskAction` methods, the work the task performs. No files are written, no tests run, no artifacts published. ## When to reach for it - Auditing what a high-level goal expands to (`./gradlew build --dry-run`). - Verifying a wiring change (`finalizedBy`, `dependsOn`) produced the ordering you intended. - Previewing before something expensive or irreversible (a `publish`, a `flywayClean`). - Teaching/onboarding: showing newcomers the shape of the graph. ## Caveats Because configuration still runs, `--dry-run` is **not** a way to test that configuration is fast or side-effect-free — it can still be slow if configuration is heavy, and configuration-time side effects (eager work outside task actions) still happen. It also does not evaluate task up-to-date / cache state in a way you can act on, since nothing executes.

  • Does --dry-run run the configuration phase?
    Yes. Initialization and configuration run normally — only the execution phase is replaced by the SKIPPED print-out. So task registration and configuration closures execute, but task actions do not.
  • Will a doLast block run under --dry-run?
    No. doFirst/doLast/@TaskAction are part of execution and are skipped. Only configuration-time code runs.

saying these in an interview costs you the question

  • Claiming --dry-run skips the configuration phase (it doesn't — only execution is skipped).
  • Saying it shows up-to-date / cache hit info for each task (nothing executes, so it can't).

context

open as a page

A teammate says they'll use --dry-run to confirm a build is fast and side-effect-free. Why is that the wrong tool, and what would you reach for instead?

level: middleimportance: should knowfreq 30%

basics

~20 s

--dry-run only previews the task graph; it still runs configuration and skips all execution, so it can't measure execution speed and won't reveal execution-time side effects. Use --profile (or task timing) to measure where time goes.

open as a page

What does the --profile flag do, and what kind of build slowness is it good at surfacing?

level: middleimportance: should knowfreq 45%

basics

~10 s

--profile makes Gradle write a timestamped HTML report under build/reports/profile/ that breaks the build down by phase — startup, settings/configuration, and task execution — so you can see where wall-clock time went.

open as a page

What does the -Dorg.gradle.internal.tasks.stats system property give you, and how does it differ from --profile?

level: seniorimportance: should knowfreq 25%

basics

~20 s

Setting -Dorg.gradle.internal.tasks.stats=true makes Gradle print, at the end of the build, an aggregate breakdown of task execution by task type and by outcome (executed, up-to-date, from-cache, skipped) — a text summary, not an HTML report.

open as a page

How would you set up a lightweight, account-free build-timing measurement step in CI using these flags, and what would you capture from it?

level: seniorimportance: nice to knowfreq 18%

basics

~10 s

Add a diagnostic build invocation with --profile to archive the HTML report as a CI artifact, and optionally -Dorg.gradle.internal.tasks.stats=true to log aggregated task-type/outcome stats. Capture the report and the log for trend review.

open as a page