skip to content

What lifecycle tasks does the Gradle 'base' plugin contribute, and what does each one mean?

level: juniorimportance: must knowfreq 70%

answer

  1. assemble = artifacts, no checks
  2. check = verification, no artifacts
  3. build = assemble + check
  4. clean = delete buildDirectory
  5. lifecycle tasks have no actions

basics

~10 s

The base plugin adds 'assemble' (build all artifacts), 'check' (run all verification like tests), 'build' (assemble + check together), and 'clean' (delete the build directory).

solid answer

~40 s

Applying the `base` plugin contributes four standard lifecycle tasks. **`assemble`** produces all the build's outputs/artifacts (e.g. archives) but runs no verification. **`check`** runs all verification tasks (tests, linters) without producing artifacts. **`build`** is the umbrella task that depends on both `assemble` and `check` — it's the default 'do everything' entry point. **`clean`** deletes the project's `layout.buildDirectory`. These are *lifecycle* tasks: they carry no actions themselves, they just aggregate work by depending on other tasks. Other plugins (like `java`) hook into them — e.g. `jar` becomes a dependency of `assemble`, and `test` becomes a dependency of `check`. This convention is why `gradle build` behaves consistently across very different project types.

code

kotlin · 10 lines
kotlin
plugins { base }

// A custom artifact task hooked into the lifecycle
val bundle by tasks.registering(Zip::class) {
    from("src/dist")
    archiveFileName.set("app.zip")
}

tasks.named("assemble") { dependsOn(bundle) }
// now `gradle build` -> assemble (runs bundle) + check

go deeper

for a junior

Name the four tasks and say one sentence each. Knowing assemble=artifacts, check=verify, build=both, clean=delete is enough.

for a middle

Explain that they are action-less lifecycle tasks and that build = assemble + check, plus how java wires jar/test into them.

for a senior

Discuss the lifecycle-base vs base split, the archives configuration, and how custom plugins should hook into the lifecycle rather than redefine it.

for a principal

Frame the lifecycle as a cross-project contract that makes gradle build uniform across heterogeneous modules, and a governance lever for org-wide build conventions.

## What the base plugin is The `base` plugin is one of Gradle's most foundational core plugins. It does not know anything about Java, Kotlin, or any language. Its entire job is to establish the **standard build lifecycle** — a small set of well-known, empty 'umbrella' tasks that every other plugin can attach work to. Because of this convention, `gradle build` means the same thing whether you're building a Java library, a C++ binary, or a documentation site. Internally `base` is split: it applies `lifecycle-base` (which contributes the lifecycle tasks and the `clean` task) and then layers on the archive/artifact conventions (the `archives` configuration, base archive naming via the `base { }` extension). ## The four lifecycle tasks These are **lifecycle tasks**: tasks with no `@TaskAction` of their own. They exist purely to depend on real work tasks, so running them runs everything wired into them. - **`assemble`** — aggregates all tasks that *produce* the project's artifacts. It performs no verification. With the `java` plugin, `jar` is wired in as a dependency, so `assemble` builds the JAR. - **`check`** — aggregates all *verification* tasks. With `java`, the `test` task is wired in. Running `check` runs your tests but does not build distributables. - **`build`** — depends on **both** `assemble` and `check`. It is the canonical 'build the whole thing and verify it' entry point. (Note: `build` is *not* the same as the `build` *directory*.) - **`clean`** — a `Delete` task that removes `layout.buildDirectory` (by default `build/`). `lifecycle-base` also lets plugins register `clean<TaskName>` rules so individual outputs can be cleaned. ## How other plugins hook in The power is in the wiring. A plugin doesn't redefine the lifecycle — it *contributes* to it: ```kotlin tasks.named("assemble") { dependsOn(myArtifactTask) } tasks.named("check") { dependsOn(myVerificationTask) } ``` This is why a single `gradle build` invocation in a multi-language project does the right thing for every plugin applied. ## The `archives` configuration `base` also creates the `archives` configuration. Artifacts added to it (e.g. via `artifacts { archives jarTask }`) are picked up by `assemble`. This is the legacy hook that older plugins used to register their outputs. ## Why it matters Most build authors apply `base` *transitively* (the `java` plugin applies it for you). You apply it directly when writing a custom plugin or a build that produces artifacts but isn't a JVM project, and you want the standard lifecycle vocabulary for free.

  • Does `assemble` run your tests?
    No. `assemble` only produces artifacts. Tests are verification and are wired into `check`. Only `build` (which depends on both) runs both.
  • What's the difference between the `build` task and the `build/` directory?
    Unrelated. `build` is a lifecycle task (assemble + check); `build/` is the default output directory (`layout.buildDirectory`) that `clean` deletes.

Think of the lifecycle tasks as labeled empty boxes on a shelf. Plugins drop their real work into the right box; running build just empties every box in order.

saying these in an interview costs you the question

  • Saying `assemble` runs tests — it explicitly does not.
  • Confusing the `build` task with the `build/` directory.
  • Thinking lifecycle tasks have their own actions rather than just aggregating dependencies.

context