Where do the group and version metadata for a published plugin come from, and how do they relate to the plugin id and marker?
answer
- impl = group:name:version
- marker = <id>:<id>.gradle.plugin:version
- id independent of group
- version = project.version = plugins {} version
- centralize version via pluginManagement / catalog
basics
~20 sThe implementation module's coordinates come from the project's group and version properties. The version requested in plugins {} must match the marker version, which derives from the same project version. The id is independent of group.
solid answer
~40 sThere are two coordinate sets for a plugin: - **Implementation module**: `project.group:project.name:project.version` — the jar that holds your `Plugin<Project>` and descriptor. - **Marker module**: `<id>:<id>.gradle.plugin:project.version` — generated from each declared id. The `id` (e.g. `com.acme.greeting`) is **separate** from the implementation `group` (which could be `com.acme`) — they need not match, which is why the marker exists to bridge them. The **version** in both the marker and implementation is `project.version`; this is the value consumers request via `plugins { id("…") version "1.0" }`. So setting `group` and `version` on the build-logic project is what drives the published metadata; the id and implementationClass live in `gradlePlugin`. If you omit a version on the consumer side, Gradle relies on `pluginManagement` version constraints or a version catalog.
code
kotlin · 11 lines// settings.gradle.kts on the consumer side — version declared once
pluginManagement {
plugins {
id("com.acme.greeting") version "1.0"
}
}
// build.gradle.kts in subprojects — no version needed
plugins {
id("com.acme.greeting")
}go deeper
Know that group and version come from the project's group/version properties.
Distinguish implementation vs marker coordinates and explain that the id is independent of group.
Discuss centralizing versions via pluginManagement/version catalogs and the metadata fields used for publishing.
Define org versioning/namespacing policy so internal plugin ids stay stable and discoverable across many repos.
## Two coordinate sets, one project When you publish a `java-gradle-plugin` project, two things are published: | Artifact | Coordinates | Source | |---|---|---| | Implementation jar | `group:name:version` | `project.group`, project name, `project.version` | | Marker (per id) | `<id>:<id>.gradle.plugin:version` | the declared `id` + `project.version` | The **id** and the **group** are deliberately independent. A team might use `group = "com.acme.build"` but expose ids like `com.acme.greeting` and `com.acme.farewell`. The marker bridges id → implementation coordinates. ## Where version comes from The `version` baked into both the marker and the implementation module is `project.version`. That is the exact value a consumer requests: ```kotlin plugins { id("com.acme.greeting") version "1.0" } ``` Gradle resolves the marker `com.acme.greeting:com.acme.greeting.gradle.plugin:1.0`, which transitively brings in `com.acme:greeting:1.0`. ## Setting the metadata ```kotlin group = "com.acme" version = "1.0" gradlePlugin { plugins { create("greeting") { id = "com.acme.greeting" implementationClass = "com.acme.GreetingPlugin" // displayName / description are used when publishing to the Plugin Portal } } } ``` ## Version management on the consumer side Consumers can avoid repeating versions by: - Declaring the version once in `settings.gradle(.kts)` `pluginManagement { plugins { id("com.acme.greeting") version "1.0" } }`, then applying without a version in subprojects. - Using a **version catalog** `[plugins]` table and `alias(libs.plugins.greeting)`. ## Common metadata fields Beyond id/implementationClass, each declaration supports `displayName` and `description` (consumed by Plugin Portal publishing). `tags` and `website`/`vcsUrl` are configured separately for portal publishing. The core resolution metadata, though, is purely id + version + the marker.
- Must the plugin id share a prefix with the implementation group?No. They are independent; the marker exists precisely to map an arbitrary id onto whatever group:name the implementation uses. Sharing a prefix is only a naming convention.
- How can consumers avoid repeating the version in every subproject?Declare it once in settings.gradle pluginManagement { plugins { … version } } or via a version catalog [plugins] alias, then apply by id alone.
saying these in an interview costs you the question
- Claiming the plugin id must equal the Maven group.
- Thinking the marker version can differ from the implementation version.
- Forgetting that project.version is the single source for the published version.