When you write `id("org.springframework.boot")` in the plugins block, what is the 'plugin marker artifact' Gradle looks up, and how does it differ from the plugin's real implementation jar?
answer
- id → marker → implementation jar (two hops)
- marker coordinate = <id>:<id>.gradle.plugin:<version>
- marker POM has no classes, one dependency
- java-gradle-plugin + maven-publish auto-generates marker
- looked up via pluginManagement repositories
basics
~20 sGradle turns the plugin id into a tiny marker module <id>:<id>.gradle.plugin whose POM has no code — it only depends on the real implementation jar. The marker redirects; the implementation jar contains the plugin classes.
solid answer
~40 sA plugin **id** is a logical name (e.g. `org.springframework.boot`). It is not a Maven coordinate, so Gradle can't fetch it directly. To resolve it, Gradle constructs a **plugin marker artifact**: a synthetic module with group=`<id>`, name=`<id>.gradle.plugin`, version=the requested plugin version. That marker is published as a POM with **no classes** — its only job is to declare a single `dependency` on the **real implementation module** (e.g. `org.springframework.boot:spring-boot-gradle-plugin`). So resolution is two hops: id → marker POM → implementation jar. This indirection lets the human-friendly id stay stable even if the implementation's group/artifact changes, and lets one id map cleanly onto standard dependency resolution. The Gradle Plugin Portal and Maven repos both serve markers this way; `java-gradle-plugin` + the `maven-publish` plugin auto-generate the marker when you publish your own plugin.
code
xml · 14 lines<!-- com.diffplug.spotless.gradle.plugin POM (the marker) -->
<project>
<groupId>com.diffplug.spotless</groupId>
<artifactId>com.diffplug.spotless.gradle.plugin</artifactId>
<version>6.25.0</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-plugin-gradle</artifactId>
<version>6.25.0</version>
</dependency>
</dependencies>
</project>go deeper
Know that an id maps to a special marker module that points at the real jar; remember the <id>:<id>.gradle.plugin shape.
Explain the two-hop resolution, that the marker is POM-only, and that markers come from pluginManagement repositories.
Discuss why the indirection exists (stable id vs movable impl), multiple ids per jar, and how java-gradle-plugin + maven-publish auto-generate markers.
Frame marker conventions for an internal plugin platform: repo layout, id namespacing, and how marker generation simplifies governance of plugin distribution.
## The problem: ids are not coordinates In the `plugins {}` block you reference a plugin by **id** — a reverse-DNS-style logical name like `com.diffplug.spotless`. A Maven/Gradle module, however, is identified by a **GAV coordinate**: `group:artifact:version`. An id is *not* a coordinate, so Gradle cannot just download `com.diffplug.spotless`. It needs a deterministic bridge from id to coordinate. ## The marker artifact That bridge is the **plugin marker artifact**. For a request `id("X") version "V"`, Gradle synthesizes a module with: - **group** = `X` - **artifact** = `X.gradle.plugin` - **version** = `V` So `id("com.diffplug.spotless") version "6.25.0"` becomes the coordinate `com.diffplug.spotless:com.diffplug.spotless.gradle.plugin:6.25.0`. This marker is published as a **POM-only module** — there is no jar with classes. Its POM contains exactly one `<dependency>`: a pointer to the **real implementation module**, e.g. `com.diffplug.spotless:spotless-plugin-gradle:6.25.0`. Gradle resolves the marker POM, follows that dependency, downloads the implementation jar, and loads the plugin classes from it. ## Why the indirection helps - **Stable id, movable implementation.** The id `com.diffplug.spotless` can stay constant while the implementation artifact gets renamed or re-grouped — only the marker's dependency changes. - **One id → standard resolution.** Once you have a coordinate, normal repository resolution, version conflict resolution, and caching all apply unchanged. - **Multiple ids, one jar.** A jar can register several plugin ids; each id gets its own marker, all pointing at the same implementation jar. ## Where markers are looked up Markers are resolved from the repositories declared in `pluginManagement { repositories { … } }` in `settings.gradle(.kts)`. By default that is the **Gradle Plugin Portal** (`https://plugins.gradle.org/m2/`), which serves both the marker POMs and (often as a proxy) the implementation jars. You can add Maven Central or a corporate repo there too. ## Publishing your own marker When you build a plugin with the `java-gradle-plugin` plugin and declare ids via the `gradlePlugin { plugins { … } }` block, then apply `maven-publish`, Gradle **auto-generates the marker module** for each declared id alongside your implementation jar at publish time. You don't hand-write the marker POM. ```kotlin gradlePlugin { plugins { create("greeting") { id = "com.example.greeting" implementationClass = "com.example.GreetingPlugin" } } } ``` Publishing the above produces both `com.example:my-plugin:1.0` (the impl jar) and the marker `com.example.greeting:com.example.greeting.gradle.plugin:1.0` that depends on it.
- Where does Gradle look up the marker, and how do you point it at a corporate repo instead of the Portal?From the repositories in `pluginManagement { repositories { … } }` in settings.gradle(.kts). Add `maven { url = … }` (and optionally `gradlePluginPortal()`) there; the order defines the search sequence.
- If a marker is just a POM with no classes, where do the plugin's actual classes come from?From the implementation jar the marker depends on. Gradle resolves the marker POM, follows its single dependency to the real implementation module, downloads that jar, and loads the plugin class from it.
The marker is like a postal redirect card: you address mail to the old name (the id), and it carries no contents itself — it just forwards everything to the real current address (the implementation jar).
saying these in an interview costs you the question
- Saying the id IS a Maven coordinate Gradle downloads directly — it isn't; a marker bridges the two.
- Claiming the marker jar contains the plugin code — the marker is POM-only with zero classes.
- Thinking you must hand-write the marker POM — java-gradle-plugin generates it on publish.