When can you apply a plugin in plugins {} without specifying a version, and how does Gradle know which version to use?
answer
- version known once
- pluginManagement.plugins centralizes
- apply false at root
- catalog alias supplies version
- conflict if two differ
basics
~10 sYou omit the version when it's already resolved elsewhere: core Gradle plugins (bundled), plugins versioned in settings' pluginManagement.plugins {}, or a version brought in by a parent/root project. Gradle reuses that already-known version.
solid answer
~40 sA version can be omitted whenever Gradle already knows it from another source. The common cases: (1) **Core plugins** (`java`, `application`) ship in the distribution and are never versioned. (2) **pluginManagement.plugins {}** in `settings.gradle.kts` centrally pins versions, so subprojects just write `id("foo")` with no version. (3) In a **multi-project build**, if the version was resolved on the build script classpath by the root or another project (e.g. via `apply false`), child projects can apply it without repeating the version. (4) A **version catalog** alias supplies the version. The unifying rule: the version only needs to appear *once* per plugin on the build classpath; after that the id alone is enough. Repeating a *different* version for the same plugin in two places triggers a conflict.
code
kotlin · 11 lines// settings.gradle.kts — define version once
pluginManagement {
plugins {
id("com.diffplug.spotless") version "6.25.0"
}
}
// any module's build.gradle.kts — apply with no version
plugins {
id("com.diffplug.spotless")
}go deeper
Recall that core plugins and catalog-aliased plugins need no version in the script.
Explain pluginManagement.plugins {} and root-resolves-then-children-omit, plus conflict behavior.
Choose a single source of truth and justify it; reason about conflicts across modules.
Standardize the resolution source org-wide and enforce it via convention plugins/settings.
## The core idea: resolve a version once Gradle builds a single *plugin resolution* picture for the build. A plugin's version must be known **once**; thereafter you can apply it by id alone. There are several ways the version becomes known: ### 1. Core / bundled plugins Plugins shipped inside the Gradle distribution (`java`, `java-library`, `application`, `jacoco`, `maven-publish`) have no external version. `id("java")` is always version-less. ### 2. Centralized in settings — pluginManagement.plugins {} ```kotlin // settings.gradle.kts pluginManagement { plugins { id("org.springframework.boot") version "3.3.0" } } ``` Now any project can apply it with just `id("org.springframework.boot")` — no version. This is a clean way to define versions in one place across modules. ### 3. Multi-project: resolve at the root with `apply false` ```kotlin // root build.gradle.kts plugins { id("org.springframework.boot") version "3.3.0" apply false } // subproject build.gradle.kts plugins { id("org.springframework.boot") // version omitted, already resolved } ``` `apply false` resolves the plugin (puts it on the classpath) **without applying** it to the root, so children apply it version-less. (The deeper mechanics of `apply false` belong to a sibling topic; here the relevant effect is that it makes the version known.) ### 4. Version catalog alias ```kotlin plugins { alias(libs.plugins.springBoot) // version comes from libs.versions.toml } ``` The catalog carries the version, so the script body has none. ## What happens if versions disagree? If two sources declare the **same plugin id with different versions** on the same classpath, Gradle reports a plugin version conflict. The fix is to pick one source of truth (catalog or pluginManagement) and omit the version everywhere else. ## Mental model Think of the version declaration as *seeding* the resolution; the bare `id("x")` is a *reference* to whatever was seeded. Junior devs often re-type the version in every module — correct but brittle; the omit-when-resolved pattern is what keeps multi-module builds DRY.
- What happens if the root declares a plugin at version 1.0 and a subproject declares the same id at 2.0?Gradle reports a plugin request/version conflict because the same id appears with conflicting versions on the build classpath. You resolve it by declaring the version in exactly one place (e.g. catalog or pluginManagement) and omitting it elsewhere.
- Does omitting the version mean the plugin is applied?Not necessarily. Omitting only references an already-resolved version. Whether it is *applied* depends on the block — `apply false` resolves without applying; a plain `id("x")` applies it.
saying these in an interview costs you the question
- Saying you can always omit versions — only when already resolved.
- Confusing 'version resolved' with 'plugin applied'.
- Claiming re-declaring the same version in every module is required.