---
title: 'Gradle Goodness: Shared Configuration With Conventions Plugin'
updated: 2023-04-04 08:09:40Z
created: 2023-04-04 08:09:40Z
tags:
  - IT
  - Gradle
  - Plugin
source: >-
  https://blog.jdriven.com/2021/02/gradle-goodness-shared-configuration-with-conventions-plugin/
---

When we have a multi-module project in Gradle we sometimes want to have dependencies, task configuration and other settings shared between the multiple modules. We can use the `subprojects` or `allprojects` blocks, but the downside is that it is not clear from the build script of the subproject where the configuration comes from. We must remember it is set from another build script, but there is no reference in the subproject to that connection. It is better to use a plugin with shared configuration and use that plugin in the subprojects. We call this a conventions plugin. This way it is explicitly visible in a subproject that the shared settings come from a plugin. Also it allows Gradle to optimize the build configuration.

The easiest way to implement the shared configuration in a plugin is using a so-called precompiled script plugin. This type of plugin can be written as a build script using the Groovy or Kotlin DSL with a filename ending with `.gradle` or `.gradle.kts`. The name of the plugin is the first part of the filename before `.gradle` or `.gradle.kts`. In our subproject we can add the plugin to our build script to apply the shared configuration. For a multi-module project we can create such a plugin in the `buildSrc` directory. For a Groovy plugin we place the file in `src/main/groovy`, for a Kotlin plugin we place it in `src/main/kotlin`.

In the following example we write a script plugin using the Kotlin DSL to apply the `java-library` plugin to a project, set some common dependencies used by all projects, configure the `Test` tasks and set the Java toolchain. First we create a `build.gradle.kts` file in the `buildSrc` directory in the root of our multi-module project and apply the `kotlin-dsl` plugin:

```kotlin
// File: buildSrc/build.gradle.kts
plugins {
    `kotlin-dsl`
}

repositories.mavenCentral()
```

Next we create the conventions plugin with our shared configuration:

```kotlin
// File: buildSrc/src/main/kotlin/java-project-conventions.gradle.kts
plugins {
    `java-library`
}

group = "mrhaki.sample"
version = "1.0"

repositories {
    mavenCentral()
}

dependencies {
    val log4jVersion: String by extra("2.14.0")
    val junitVersion: String by extra("5.3.1")
    val assertjVersion: String by extra("3.19.0")

    // Logging
    implementation("org.apache.logging.log4j:log4j-api:${log4jVersion}")
    implementation("org.apache.logging.log4j:log4j-core:${log4jVersion}")

    // Testing
    testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
    testImplementation("org.assertj:assertj-core:${assertjVersion}")
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(15))
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}
```

The id of our new plugin is `java-project-conventions` and we can use it in our build script for a subproject as:

```kotlin
// File: rest-api/build.gradle.kts
plugins {
    id("java-project-conventions")  // apply shared config
    application  // apply the Gradle application plugin
}

dependencies {
    val vertxVersion: String by extra("4.0.2")

    implementation(project(":domain"))  // project dependency
    implementation("io.vertx:vertx-core:${vertxVersion}")
}

application {
    mainClass.set("com.mrhaki.web.Api")
}
```

The `rest-api` project will have all the configuration and tasks from `java-library` plugin as configured in the `java-project-conventions` plugin, so we can build it as a Java project.

Written with Gradle 6.8.2.