Skip to content

Installing

This page lists the settings a project needs before its first module builds. We pasted each step into an empty project and built it, in the order shown here. Follow it top to bottom and the last step compiles.

Requirements

Gradle has to run on Java 21 or newer. On an older JVM the build fails while resolving the plugin itself. The error talks about the JVM runtime version, not about the plugin.

Repositories

The plugins are published to Maven Central. The Gradle plugin portal already reads Maven Central, so the portal alone is enough to find them. It isn't enough to build with them, though. They depend on the Android Gradle plugin, which is only published to Google's repository. Without google(), the build fails while resolving com.android.tools.build:gradle. That names a plugin you never asked for, which is confusing.

Add both to settings.gradle.kts:

pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
    }
}

dependencyResolutionManagement {
    repositories {
        mavenCentral()
        google()
    }
}

Version catalog

The plugins read versions from a catalog named libs. So gradle/libs.versions.toml has to exist, even in a project that wouldn't otherwise have one.

Three versions are always required. A module targeting Android needs three more.

[versions]
app-gradle-plugins = "0.8.8"

java-target = "21"
java-toolchain = "21"
ktlint = "1.8.0"

# Android modules only
android-compile = "36"
android-min = "26"
android-target = "36"

# The plugins the suite applies on your behalf, see the next section
agp = "9.3.1"
kotlin = "2.4.10"
spotless = "8.9.0"

[plugins]
app-root = { id = "io.github.thomaskioko.gradle.plugins.root", version.ref = "app-gradle-plugins" }
app-android = { id = "io.github.thomaskioko.gradle.plugins.android", version.ref = "app-gradle-plugins" }
app-application = { id = "io.github.thomaskioko.gradle.plugins.app", version.ref = "app-gradle-plugins" }
app-jvm = { id = "io.github.thomaskioko.gradle.plugins.jvm", version.ref = "app-gradle-plugins" }
app-kmp = { id = "io.github.thomaskioko.gradle.plugins.multiplatform", version.ref = "app-gradle-plugins" }
app-baseline-profile = { id = "io.github.thomaskioko.gradle.plugins.baseline.profile", version.ref = "app-gradle-plugins" }
app-buildconfig = { id = "io.github.thomaskioko.gradle.plugins.buildconfig", version.ref = "app-gradle-plugins" }
app-resource-generator = { id = "io.github.thomaskioko.gradle.plugins.resource.generator", version.ref = "app-gradle-plugins" }
app-spotless = { id = "io.github.thomaskioko.gradle.plugins.spotless", version.ref = "app-gradle-plugins" }

android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }

Options inside scaffold {} read more entries when you switch them on. useMetro() reads metro-runtime, useCodegen() reads codegen-annotations and codegen-processor, and so on. Each option's documentation names the entries it looks for.

Root project

The root project does two jobs. First, it applies the root plugin, which sets up dependency analysis for the whole build. Second, it names every plugin any module will use. That way a module can apply one without repeating the version.

You declare everything a module applies here, with apply false. That puts the plugin on the build classpath without applying it to the root project. If you leave one out, the module that applies it fails. The error says the plugin is already on the classpath with an unknown version.

plugins {
    alias(libs.plugins.spotless) apply false
    alias(libs.plugins.android.library) apply false
    alias(libs.plugins.kotlin.multiplatform) apply false

    alias(libs.plugins.app.root)
    alias(libs.plugins.app.android) apply false
    alias(libs.plugins.app.jvm) apply false
    alias(libs.plugins.app.kmp) apply false
}

Applied plugins

Three declarations cover the whole suite, because these plugins ship together. Naming com.android.library puts every Android plugin on the classpath. Naming one Kotlin plugin puts the rest there too.

Applied to every module: Spotless and dependency analysis.

Applied by the plugin you chose: com.android.application for app, com.android.library and com.android.lint for android, org.jetbrains.kotlin.jvm for jvm, and org.jetbrains.kotlin.multiplatform for multiplatform.

Applied only when you ask for them in scaffold {}: KSP, Metro, Compose, Kotlin serialization, Roborazzi, dependency guard, baseline profiles, Google Services and Crashlytics. Each option's documentation says what it applies and what it reads from the catalog.

Android namespace

Android modules build their namespace from the module path plus one property. Add it to gradle.properties:

package.name=com.example.myapp

Module setup

Each module applies one plugin and describes itself through scaffold {}.

plugins {
    alias(libs.plugins.app.kmp)
}

scaffold {
    useMetro()
}

There are four platform plugins. app is for an Android application, android for an Android library, jvm for a plain Kotlin library, and multiplatform for a Kotlin Multiplatform library. Pick one per module.

Formatting

The suite runs Spotless over your build files as well as your source, with four spaces for indentation. Every sample here uses four spaces, so pasting one keeps the build green. If you paste something indented with two spaces, the first build reports a formatting violation in the file you just wrote.

Next steps

The API reference covers every plugin, every option in scaffold {} and every annotation. We generate it from the source.