skip to content

Where do the group and version metadata for a published plugin come from, and how do they relate to the plugin id and marker?

level: middleimportance: should knowfreq 40%

answer

  1. impl = group:name:version
  2. marker = <id>:<id>.gradle.plugin:version
  3. id independent of group
  4. version = project.version = plugins {} version
  5. centralize version via pluginManagement / catalog

basics

~20 s

The 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 s

There 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
kotlin
// 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

for a junior

Know that group and version come from the project's group/version properties.

for a middle

Distinguish implementation vs marker coordinates and explain that the id is independent of group.

for a senior

Discuss centralizing versions via pluginManagement/version catalogs and the metadata fields used for publishing.

for a principal

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.

context