A convention plugin is a type of pre-compiled script plugin.

A convention plugin is a plugin that normally configures existing core and community plugins with your own conventions (i.e. default values) such as setting the Java version by using java.toolchain.languageVersion = JavaLanguageVersion.of(17).

Convention plugins are also used to enforce project standards and help streamline the build process. They can apply and configure plugins, create new tasks and extensions, set dependencies, and much more.

Convention plugins are preferred over allprojects {} / subprojects {} blocks.

Creating a convention plugin

Convention plugins are typically placed in either:

  • buildSrc/ — simplest approach, automatically on the classpath of the build.

  • an included build (commonly named build-logic/) — more scalable, especially for multi-project builds or organizations.

Any .gradle.kts (or .gradle) script file in src/main/kotlin/ or src/main/groovy/ of that plugin build becomes a precompiled script plugin, and its file name defines the plugin ID.

Example of a convention plugin

Convention plugins really shine when you want to capture organization-wide defaults once, and apply them consistently across many subprojects.

Imagine you want every module that publishes artifacts to use the same Maven configuration. Instead of copy–pasting publishing { … } blocks into every build.gradle(.kts), you can extract them into a convention plugin.

The project layout is as follows:

.
├── core/
├── utils/
├── platform/
└── buildSrc/
    ├── build.gradle.kts
    └── src/
        └── main/
            └── kotlin/
                └── java-conventions.gradle.kts
.
├── core/
├── utils/
├── platform/
└── buildSrc/
    ├── build.gradle
    └── src/
        └── main/
            └── groovy/
                └── java-conventions.gradle

Here’s a precompiled script plugin that standardizes publishing. Notice how it sets the group and version from the root project and configures a local Maven repository in build/repo:

buildSrc/src/main/kotlin/myproject.publishing-conventions.gradle.kts
plugins {
    id("maven-publish")
}

group = rootProject.group
version = rootProject.version

publishing {
    repositories {
        maven {
            url = uri(rootProject.layout.buildDirectory.dir("repo"))
        }
    }
}
buildSrc/src/main/groovy/myproject.publishing-conventions.gradle
plugins {
    id 'maven-publish'
}

group = rootProject.group
version = rootProject.version

publishing {
    repositories {
        maven {
            url = layout.buildDirectory.dir("repo")
        }
    }
}

With this in place, any subproject can opt in simply by applying id("myproject.publishing-conventions").

Our platform subproject applies the convention plugin alongside the java-platform plugin. It declares dependency constraints and sets up a publication for the BOM:

platform/build.gradle.kts
plugins {
    `java-platform`
    id("myproject.publishing-conventions")
}

publishing {
    publications {
        create("maven", MavenPublication::class.java) {
            from(components["javaPlatform"])
        }
    }
}
platform/build.gradle
plugins {
    id 'java-platform'
    id 'myproject.publishing-conventions'
}

publishing {
    publications {
        maven(MavenPublication) {
            from components.javaPlatform
        }
    }
}