skip to content

What is the difference between the `base` plugin and the `lifecycle-base` plugin?

level: middleimportance: should knowfreq 45%

answer

  1. lifecycle-base = tasks only
  2. base = lifecycle-base + archives
  3. base { } extension -> archivesName
  4. archives configuration feeds assemble
  5. java applies base transitively

basics

~10 s

lifecycle-base is the smaller plugin that only adds the lifecycle tasks (assemble, check, build) and clean. base applies lifecycle-base and adds archive conventions like the archives configuration and the base { } naming extension.

solid answer

~40 s

They are layered. **`lifecycle-base`** is the minimal core: it contributes the action-less lifecycle tasks `assemble`, `check`, `build`, and the `clean` (`Delete`) task, plus the rule that lets plugins register `clean<Task>` tasks. It knows nothing about artifacts. **`base`** applies `lifecycle-base` and then adds artifact/archive conventions: it creates the `archives` (and historically `default`) configuration, and adds the `base { }` extension for controlling archive base names (`archivesName`), the libs and dist output directories. So if all you need is the lifecycle vocabulary for a custom plugin, you can apply `lifecycle-base`; if you also produce archives and want the conventional naming, you apply `base`. In practice the `java` plugin (and most language plugins) apply `base` for you, so you rarely apply either directly.

code

kotlin · 7 lines
kotlin
plugins { base }

base {
    archivesName = "my-service"   // -> build/libs/my-service-<version>.jar
    libsDirectory.set(layout.buildDirectory.dir("libs"))
    distsDirectory.set(layout.buildDirectory.dir("distributions"))
}

go deeper

for a junior

Knowing that base is the bigger one and adds archive stuff on top of the lifecycle tasks is acceptable.

for a middle

State clearly that base = lifecycle-base + archives configuration + base{} extension, and that lifecycle-base is artifact-agnostic.

for a senior

Explain why the split exists (reuse of lifecycle vocabulary by non-artifact plugins) and which constants/extensions each exposes.

for a principal

Discuss choosing the minimal applied plugin in custom-plugin design to keep convention surface small and avoid leaking archive concerns into pure-orchestration plugins.

## Two plugins, one stack Gradle deliberately splits this functionality so plugin authors can pick the minimal surface they need. ### `lifecycle-base` — the pure lifecycle Applying `lifecycle-base` gives you exactly: - **`assemble`**, **`check`**, **`build`** — empty lifecycle tasks (build = assemble + check). - **`clean`** — a `Delete` task pointed at `layout.buildDirectory`. - A **rule** that materializes `clean<SomeTask>` tasks on demand, so any task's outputs can be cleaned individually. - The `LifecycleBasePlugin` also defines well-known group/name constants (`BUILD_GROUP`, `VERIFICATION_GROUP`, `ASSEMBLE_TASK_NAME`, etc.) that other plugins reference instead of hardcoding strings. That's it — no concept of artifacts, archives, or output naming. ### `base` — lifecycle + archive conventions `base` does `apply(LifecycleBasePlugin::class)` and then adds: - The **`archives`** configuration (a consumable bucket for the project's published archives). Artifacts placed here are wired into `assemble`. - The **`base { }`** extension (`BasePluginExtension`) exposing `archivesName`, `libsDirectory`, and `distsDirectory`. This is how you set, e.g., `base { archivesName = "my-lib" }` so produced JAR/ZIP files get a consistent base file name. - Conventions linking those output directories under `build/libs` and `build/distributions`. ## When you'd apply each directly - **Custom plugin that only orchestrates work** (no artifacts): apply `lifecycle-base` so your tasks can attach to `assemble`/`check` and users get a familiar `build`. - **Build that produces archives but isn't a JVM project**: apply `base` to get `archives` + naming for free. - **JVM project**: you almost never apply either — `java`/`java-library`/`application` pull in `base` transitively. ```kotlin // Minimal custom-plugin lifecycle only: plugins { id("lifecycle-base") } // Archive-producing non-JVM build: plugins { base } base { archivesName = "reports-bundle" } ``` ## Why the split exists Keeping `lifecycle-base` free of artifact concerns means the verification/aggregation vocabulary can be reused by plugins that have nothing to publish (e.g. a pure linting or codegen plugin), without dragging in archive configurations they'd never use.

  • If you only apply `lifecycle-base`, can you set `base { archivesName = ... }`?
    No. The `base { }` extension and the `archives` configuration come from the `base` plugin, not `lifecycle-base`. You'd get an unresolved extension error.
  • Which one does the `java` plugin apply?
    It applies `base` (which transitively applies `lifecycle-base`), so JVM projects get both the lifecycle and the archive conventions.

saying these in an interview costs you the question

  • Claiming `lifecycle-base` provides the `archives` configuration — that's `base`.
  • Saying they are interchangeable; `base` is strictly a superset.
  • Forgetting that language plugins apply `base` for you.

context