What is a 'plugin marker' artifact, and why does the Plugin Portal publish one alongside your implementation JAR?
answer
- id -> Maven coordinates bridge
- <id>:<id>.gradle.plugin:<version>
- POM with single dependency on impl JAR
- java-gradle-plugin generates markers
- needed for plugins{} resolution
basics
~10 sA marker is a tiny artifact at <pluginId>:<pluginId>.gradle.plugin whose POM just depends on your real implementation JAR. It lets the plugins { id … } block map a plugin ID to Maven coordinates.
solid answer
~40 sThe `plugins { id("x") version "1.0" }` DSL references plugins by **ID**, but artifact repositories resolve by **Maven coordinates** (`group:artifact:version`). The **plugin marker** bridges that gap: for each plugin ID, Gradle publishes a separate artifact at coordinates **`<id>:<id>.gradle.plugin:<version>`** whose POM contains a single `dependencies` entry pointing at your actual implementation artifact (your `group:artifact`). When a consumer requests a plugin by ID from a `pluginManagement` repository, Gradle looks up `<id>:<id>.gradle.plugin`, reads its POM, and transitively pulls the real plugin code. The `com.gradle.plugin-publish` plugin (and `java-gradle-plugin` for custom repos) generates these markers automatically — you don't hand-write them. This is why publishing to a custom Maven repo for plugin-ID resolution also requires markers, not just the JAR.
code
groovy · 12 lines// Consumer side — resolves via the marker artifact automatically
pluginManagement {
repositories {
gradlePluginPortal() // default; serves markers + impl JARs
maven { url = uri('https://my.repo/releases') }
}
}
// settings or build:
plugins {
id 'com.example.greeting' version '1.0.0'
}go deeper
Awareness only: there's a small extra artifact that makes plugin-ID resolution work.
Know the <id>:<id>.gradle.plugin naming and that it points to the real JAR.
Explain the full ID→coordinates resolution flow and which plugin generates markers for Portal vs custom repos.
Reason about marker implications when designing an internal plugin repository and migration off the Portal.
## The ID-vs-coordinates problem Gradle's `plugins {}` block is intentionally decoupled from Maven coordinates — you write `id("com.example.greeting")`, not `com.example:greeting`. But a Maven/Ivy repository can only be queried by **coordinates**. Something has to translate an ID into coordinates. ## The marker as a redirect That translation is the **plugin marker artifact**. By convention, plugin ID `com.example.greeting` maps to the marker coordinates: ``` com.example.greeting:com.example.greeting.gradle.plugin:<version> ``` The marker has **no code** — its POM declares exactly one dependency on the real implementation artifact: ```xml <dependencies> <dependency> <groupId>com.example</groupId> <artifactId>greeting</artifactId> <version>1.0.0</version> </dependency> </dependencies> ``` ## Resolution flow 1. Consumer writes `plugins { id("com.example.greeting") version "1.0.0" }`. 2. Gradle derives the marker coordinates `com.example.greeting:com.example.greeting.gradle.plugin:1.0.0`. 3. It resolves the marker POM from a configured `pluginManagement` repository (the Portal is included by default). 4. The marker's single dependency drags in the real `com.example:greeting:1.0.0` JAR, which is added to the build's classpath. ## Who generates markers - **`com.gradle.plugin-publish`** generates and uploads markers when publishing to the **Portal**. - **`java-gradle-plugin`** generates the `…PluginMarkerMaven` publications when you use `maven-publish` to push plugins to your **own** Maven repository. ## Practical implications - If you publish a plugin JAR to a custom repo but **forget the marker**, consumers using `plugins { id … }` can't resolve it (they'd have to fall back to `buildscript { dependencies … }`). - Plugin `group`/`version` for the marker default to the project's `group`/`version`, so keep those consistent.
- If you publish a plugin to a private Maven repo without markers, can consumers still use the `plugins {}` block?No. Without the marker artifact, `plugins { id … }` resolution fails; they'd have to fall back to the legacy `buildscript { dependencies { classpath … } }` plus `apply plugin:`.
- What plugin generates the marker publication for a custom Maven repository?`java-gradle-plugin` — it creates `<name>PluginMarkerMaven` publications that `maven-publish` then uploads.
saying these in an interview costs you the question
- Saying the marker contains the plugin code — it only contains a POM with one dependency.
- Believing you must hand-author marker artifacts.
- Claiming `plugins {}` resolves by Maven coordinates directly.