Walk through what happens, step by step, when a developer runs ./gradlew build on a fresh clone.
answer
- script finds Java
- runs GradleWrapperMain
- reads properties for pinned version
- cache ~/.gradle/wrapper/dists
- download once, then delegate
basics
~10 sgradlew finds Java and runs gradle-wrapper.jar; the jar reads gradle-wrapper.properties, downloads the named Gradle distribution to the cache if absent, then delegates to that Gradle to execute the build task.
solid answer
~40 sOn a fresh clone, `./gradlew build` chains through the wrapper: 1. The `gradlew` shell script resolves a Java runtime (via `JAVA_HOME`/`PATH`) and computes the classpath to `gradle/wrapper/gradle-wrapper.jar`. 2. It runs the jar's main class, `org.gradle.wrapper.GradleWrapperMain`, passing your arguments (`build`). 3. The bootstrap reads `gradle/wrapper/gradle-wrapper.properties` to learn exactly which Gradle distribution is pinned. 4. It checks the local cache (default `~/.gradle/wrapper/dists`). If the distribution is absent, it downloads and unpacks it there; if present, it reuses it. 5. It hands off to the real Gradle in that distribution, which finally runs `build`. The download/unpack happens only on first use of a given version; subsequent runs are cache hits, so the wrapper adds negligible overhead. This is exactly how a JDK-only machine ends up running the project's pinned Gradle.
code
bash · 6 lines$ ./gradlew build
Downloading https://services.gradle.org/distributions/gradle-8.7-bin.zip
...........10%...........30%...........60%...........100%
BUILD SUCCESSFUL
# Second run of any project pinning 8.7: no download (cache hit)go deeper
Roughly: gradlew runs the jar, the jar downloads Gradle if needed, then runs your task.
Name the ordered steps and that the properties file supplies the pinned version.
Detail the cache in the Gradle user home, download-once behavior, and where each step can fail.
Discuss tuning GRADLE_USER_HOME for CI cache persistence and the bootstrap-vs-distribution separation as a design choice.
## The chain of hand-offs Running `./gradlew build` is a small relay. Understanding each hop demystifies wrapper errors. ### Step 1 — the script finds Java `gradlew` is a launcher, not Gradle. It locates a JVM (preferring `JAVA_HOME`, else `java` on `PATH`) and builds the command to run the wrapper jar. (`gradlew.bat` does the same on Windows.) No JDK ⇒ it fails here. ### Step 2 — run the bootstrap jar The script executes the tiny `gradle/wrapper/gradle-wrapper.jar`, whose entry point is `org.gradle.wrapper.GradleWrapperMain`. If the jar is missing (e.g. not committed), you get *'Could not find or load main class org.gradle.wrapper.GradleWrapperMain'* right here. ### Step 3 — read the pin The bootstrap reads `gradle/wrapper/gradle-wrapper.properties` to find the **exact** distribution it must use. This is where the per-project version pin is honored. ### Step 4 — resolve from the cache Gradle distributions live in the **Gradle user home**, by default `~/.gradle/wrapper/dists` (overridable via `GRADLE_USER_HOME`). The bootstrap: - computes the cache slot for the pinned distribution, - if absent: downloads the archive, unpacks it, and marks it ready, - if present: skips straight to using it. This caching is why only the *first* build on a machine pays the download cost; every later build of any project pinning that version is a cache hit. ### Step 5 — delegate to real Gradle Finally the bootstrap invokes the actual Gradle runtime from the resolved distribution, which configures the project and executes the `build` task. ```text ./gradlew build └─ gradlew (find Java) └─ gradle-wrapper.jar (GradleWrapperMain) └─ reads gradle-wrapper.properties (pinned version) └─ ~/.gradle/wrapper/dists (download if missing, else reuse) └─ real Gradle runs 'build' ``` ## Why this design Separating a *tiny committed bootstrap* from a *large cached distribution* keeps the repo small while still pinning the version. The cache shared across projects means versions are downloaded at most once per machine. ## Failure-mode map - Java not found → fails at step 1. - Missing/renamed jar → 'GradleWrapperMain' error at step 2. - Unreadable/wrong properties → can't determine the version at step 3. - No network on first run → download fails at step 4 (later runs are fine once cached).
- Why does only the first build on a machine download Gradle?The distribution is unpacked into the shared Gradle user home cache (~/.gradle/wrapper/dists). Later runs of any project pinning that version reuse the cached copy, so there's no re-download.
- Where is the downloaded distribution stored, and can it be changed?By default under ~/.gradle/wrapper/dists in the Gradle user home; set GRADLE_USER_HOME to relocate it, which is common on CI to enable cache persistence.
saying these in an interview costs you the question
- Thinking the wrapper re-downloads Gradle on every run.
- Believing the jar runs the build itself rather than delegating to a downloaded distribution.
- Forgetting that no JDK means the script fails before any download.