To share a Gradle plugin, package it into JAR files and generate the accompanying metadata so other builds can resolve and apply it.

Gradle’s publishing plugins add tasks and conventions to prepare artifacts and metadata for distribution to repositories such as a local Maven repository, Maven Central, JFrog Artifactory, or the Gradle Plugin Portal.

Applying a Publishing Plugin

Apply one or more publishing plugins in your plugin project:

plugins {
    id("maven-publish")                                         // Maven
    id("ivy-publish")                                           // Ivy
    id("com.gradle.plugin-publish") version "<latest-version>"  // Plugin Portal
}

Applying a publishing plugin registers tasks that assemble your plugin JAR(s) and generate metadata files (POM, Gradle Module Metadata, and the plugin marker module).

Minimum Configuration

A plugin project must at least declare:

  • A plugin ID and implementation class (so Gradle knows what to apply)

  • A group and version (so the plugin can be published and resolved)

build.gradle.kts
group = "org.example"
version = "1.0"
gradlePlugin {
    plugins.create("greeting") {
        id = "org.example.greeting"
        implementationClass = "org.example.GreetingPlugin"
    }
}
build.gradle
group = 'org.example'
version = '1.0'
gradlePlugin {
    plugins.create('greeting') {
        id = 'org.example.greeting'
        implementationClass = 'org.example.GreetingPlugin'
    }
}

This lets Gradle generate the plugin marker module (org.example.greeting.gradle.plugin) and other metadata required by repositories and consumers.

Local Publishing and Testing

Before publishing remotely, publish to a local Maven directory:

build.gradle.kts
publishing {
    repositories {
        maven { url = uri(layout.buildDirectory.dir("local-repo")) }
    }
}
build.gradle
publishing {
    repositories {
        maven { url = layout.buildDirectory.dir('local-repo') }
    }
}

Run:

./gradlew publish

Gradle writes plugin artifacts and metadata to build/local-repo:

build/local-repo/
└── org/
    └── example/
        ├── greeting/
        │   └── 1.0.0/
        │       ├── greeting-1.0.0.jar                 // compiled plugin classes
        │       ├── greeting-1.0.0.jar.sha1            // checksum (SHA-1)
        │       ├── greeting-1.0.0.jar.sha256          // checksum (SHA-256)
        │       ├── greeting-1.0.0.module              // Gradle Module Metadata (variants, capabilities, deps)
        │       ├── greeting-1.0.0.module.sha1
        │       ├── greeting-1.0.0.module.sha256
        │       ├── greeting-1.0.0.pom                 // Maven POM: GAV + dependencies
        │       ├── greeting-1.0.0.pom.sha1
        │       ├── greeting-1.0.0.pom.sha256
        │       └── greeting-1.0.0-sources.jar         // optional (java { withSourcesJar() })
        │           ├── greeting-1.0.0-sources.jar.sha1
        │           └── greeting-1.0.0-sources.jar.sha256
        │
        └── org.example.greeting.gradle.plugin/
            └── 1.0.0/
                ├── org.example.greeting.gradle.plugin-1.0.0.module         // plugin marker metadata
                ├── org.example.greeting.gradle.plugin-1.0.0.module.sha1
                ├── org.example.greeting.gradle.plugin-1.0.0.module.sha256
                ├── org.example.greeting.gradle.plugin-1.0.0.pom            // plugin marker POM
                ├── org.example.greeting.gradle.plugin-1.0.0.pom.sha1
                └── org.example.greeting.gradle.plugin-1.0.0.pom.sha256

You’ll see:

  • Plugin JAR(s) — compiled classes

  • .pom — Maven metadata (coordinates, dependencies)

  • .module — Gradle Module Metadata (variants, capabilities)

  • Plugin marker module — enables plugins { id("…") } resolution by plugin ID

  • Optional sources JAR — if enabled via withSourcesJar()

  • Checksums — integrity files (many repos prefer SHA-256/SHA-512)

To consume locally, point the consumer project’s pluginManagement to the local repo:

settings.gradle.kts
pluginManagement {
    repositories {
        maven {
            url = uri("../plugin/build/local-repo")
        }
        gradlePluginPortal()
    }
}
settings.gradle
pluginManagement {
    repositories {
        maven {
            url = uri('../plugin/build/local-repo')
        }
        gradlePluginPortal()
    }
}

Consumers can then apply your plugin by ID without publishing to a public repository.

Validating

To validate a Plugin Portal publication (no upload):

$ ./gradlew publishPlugins --validate-only