# Initialization Scripts and Init Plugins

version 9.8.0-milestone-2

Initialization scripts (init scripts) are Gradle scripts that run during the initialization phase, before the build’s `settings.gradle(.kts)` and project build scripts are evaluated.

Init scripts are useful for setting up common configuration such as enterprise repositories, plugin resolution rules, build listeners, or applying custom plugins across many builds without modifying each repository.

| Init scripts affect every build they are attached to (local or CI), so treat them like production code.

## Using an init script

Init scripts are Groovy/Kotlin scripts whose receiver is the `Gradle` object.

They can:

- Configure enterprise-wide defaults (e.g., `pluginManagement`, mirrors)

- Vary configuration by environment (dev vs. CI)

- Provide user-specific data (e.g., credentials via providers)

- Define machine-specific details (e.g., JDK/SDK locations)

- Register build listeners and custom loggers

One important limitation is that init scripts cannot access classes from `buildSrc` in the target build.

## Invoking an init script

Init scripts are discovered and executed in this order:

1. Command line: `-I` / `--init-script path/to/init.gradle(.kts)` (can be repeated)

2. `$GRADLE_USER_HOME/init.gradle(.kts)`

3. Any `\*.init.gradle(.kts)` in `$GRADLE_USER_HOME/init.d/` (alphabetical)

4. Any `\*.init.gradle(.kts)` in `$GRADLE_HOME/init.d/` (alphabetical)

All found scripts run; scripts in the same directory run alphabetically.

## Writing an init script

Like any Gradle script, an init script implements `Script` and delegates to the `Gradle` instance.

| Properties from `gradle.properties` are available on `Settings`/`Project`, not on `Gradle`.

Useful `Gradle` callbacks include: `settingsEvaluated {}`, `projectsLoaded {}`, `beforeProject {}`, `afterProject {}`. You can see more in the Gradle Lifecycle API.

### Configuring projects from an init script

You can use an init script to configure the projects in the build. This works similarly to configuring projects in a multi-project build.

The following sample shows how to perform extra configuration from an init script before the projects are evaluated:

build.gradle

    repositories {
        mavenCentral()
    }

    tasks.register('showRepos') {
        def repositoryNames = repositories.collect { it.name }
        doLast {
            println "All repos:"
            println repositoryNames
        }
    }

init.gradle

    allprojects {
        repositories {
            mavenLocal()
        }
    }

build.gradle.kts

    repositories {
        mavenCentral()
    }

    tasks.register("showRepos") {
        val repositoryNames = repositories.map { it.name }
        doLast {
            println("All repos:")
            println(repositoryNames)
        }
    }

init.gradle.kts

    allprojects {
        repositories {
            mavenLocal()
        }
    }

This sample uses this feature to configure an additional repository to be used only for specific environments.

    $ ./gradlew --init-script init.gradle.kts -q showRepos

    All repos:
    [MavenLocal, MavenRepo]

    $ ./gradlew --init-script init.gradle -q showRepos

    All repos:
    [MavenLocal, MavenRepo]

## Adding external dependencies

Use `initscript { }` to declare the init script’s classpath (repositories + dependencies):

init.gradle.kts

    initscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath("org.apache.commons:commons-math:2.0")
        }
    }

init.gradle

    initscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath 'org.apache.commons:commons-math:2.0'
        }
    }

The closure passed to `initscript` configures a `ScriptHandler` instance. You declare the init script classpath by adding dependencies to the `classpath` configuration.

This is the same way you declare, for example, the Java compilation classpath. You can use any of the dependency types described in Declaring Dependencies, except project dependencies.

Having declared the init script classpath, you can use the classes in your init script as you would any other classes on the classpath. The following example adds to the previous example and uses classes from the init script classpath:

init.gradle.kts

    import org.apache.commons.math.fraction.Fraction

    initscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath("org.apache.commons:commons-math:2.0")
        }
    }

    println(Fraction.ONE_FIFTH.multiply(2))

build.gradle.kts

    tasks.register("doNothing")

init.gradle

    import org.apache.commons.math.fraction.Fraction

    initscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath 'org.apache.commons:commons-math:2.0'
        }
    }

    println Fraction.ONE_FIFTH.multiply(2)

build.gradle

    tasks.register('doNothing')

    $ ./gradlew --init-script init.gradle.kts -q doNothing

    2 / 5

    $ ./gradlew --init-script init.gradle -q doNothing

    2 / 5

## Init plugins

An init plugin is a Gradle plugin whose target type is `Plugin<Gradle>` and is applied in an init script.

Unlike project (`Plugin<Project>`) or settings (`Plugin<Settings>`) plugins, an init plugin attaches to the Gradle object during the initialization phase, before the settings and projects are configured:

- Scope: Runs at init; can access `settingsEvaluated`, `projectsLoaded`, `beforeProject`, `afterProject` callbacks to safely interact with settings/projects when they exist.

- Distribution: Applied from an init script (`~/.gradle/init.d/*.init.gradle(.kts)` or `$GRADLE_HOME/init.d`) so it affects every build on that machine/agent. However, this does not include all builds: for example, builds run via `TestKit` use an isolated Gradle user home, and different users or build agents may each have their own init scripts.

The init plugin in the init script ensures that only a specified repository is used when running the build:

init.gradle.kts

    apply<EnterpriseRepositoryPlugin>()

    class EnterpriseRepositoryPlugin : Plugin<Gradle> {
        companion object {
            const val ENTERPRISE_REPOSITORY_URL = "https://repo.gradle.org/gradle/repo"
        }

        override fun apply(gradle: Gradle) {
            // ONLY USE ENTERPRISE REPO FOR DEPENDENCIES
            gradle.allprojects {
                repositories {

                    // Remove all repositories not pointing to the enterprise repository url
                    all {
                        if (this !is MavenArtifactRepository || url.toString() != ENTERPRISE_REPOSITORY_URL) {
                            project.logger.lifecycle("Repository ${(this as? MavenArtifactRepository)?.url ?: name} removed. Only $ENTERPRISE_REPOSITORY_URL is allowed")
                            remove(this)
                        }
                    }

                    // add the enterprise repository
                    add(maven {
                        name = "STANDARD_ENTERPRISE_REPO"
                        url = uri(ENTERPRISE_REPOSITORY_URL)
                    })
                }
            }
        }
    }

build.gradle.kts

    repositories{
        mavenCentral()
    }

    data class RepositoryData(val name: String, val url: URI)

    tasks.register("showRepositories") {
        val repositoryData = repositories.withType<MavenArtifactRepository>().map { RepositoryData(it.name, it.url) }
        doLast {
            repositoryData.forEach {
                println("repository: ${it.name} ('${it.url}')")
            }
        }
    }

init.gradle

    apply plugin: EnterpriseRepositoryPlugin

    class EnterpriseRepositoryPlugin implements Plugin<Gradle> {

        private static String ENTERPRISE_REPOSITORY_URL = "https://repo.gradle.org/gradle/repo"

        void apply(Gradle gradle) {
            // ONLY USE ENTERPRISE REPO FOR DEPENDENCIES
            gradle.allprojects { project ->
                project.repositories {

                    // Remove all repositories not pointing to the enterprise repository url
                    all { ArtifactRepository repo ->
                        if (!(repo instanceof MavenArtifactRepository) ||
                              repo.url.toString() != ENTERPRISE_REPOSITORY_URL) {
                            project.logger.lifecycle "Repository ${repo.url} removed. Only $ENTERPRISE_REPOSITORY_URL is allowed"
                            remove repo
                        }
                    }

                    // add the enterprise repository
                    maven {
                        name = "STANDARD_ENTERPRISE_REPO"
                        url = ENTERPRISE_REPOSITORY_URL
                    }
                }
            }
        }
    }

build.gradle

    repositories{
        mavenCentral()
    }

    @Immutable
    class RepositoryData {
        String name
        URI url
    }

    tasks.register('showRepositories') {
        def repositoryData = repositories.collect { new RepositoryData(it.name, it.url) }
        doLast {
            repositoryData.each {
                println "repository: ${it.name} ('${it.url}')"
            }
        }
    }

    $ ./gradlew --init-script init.gradle.kts -q showRepositories

    repository: STANDARD_ENTERPRISE_REPO ('https://repo.gradle.org/gradle/repo')

    $ ./gradlew --init-script init.gradle -q showRepositories

    repository: STANDARD_ENTERPRISE_REPO ('https://repo.gradle.org/gradle/repo')

## Applying plugins from an init script

You can apply plugins in an init script just like in `build.gradle(.kts)`/`settings.gradle(.kts)`.

When applying plugins within the init script, Gradle instantiates the plugin and calls the plugin instance’s `Plugin.apply(T)` method.

The `gradle` object is passed as a parameter, which can be used to configure all aspects of a build. Of course, the applied plugin can be resolved as an external dependency as described in External dependencies for the init script.

In this example, the init script is its own project called `baseline-init-plugin`:

baseline-init-plugin/src/main/kotlin/com/example/BaselineInitPlugin.kt

    package com.example

    import org.gradle.api.Plugin
    import org.gradle.api.invocation.Gradle
    import org.gradle.api.initialization.Settings

    class BaselineInitPlugin : Plugin<Gradle> {
        override fun apply(gradle: Gradle) {
            println("[INIT-PLUGIN] apply() called")

            // Project-time: apply lightweight conventions
            gradle.beforeProject { project ->
                project.repositories.apply {
                    if (isEmpty()) {
                        println("🔧 [INIT-PLUGIN] Adding default repositories to ${project.name}")
                        mavenCentral()
                        google()
                    }
                }
            }
        }
    }

baseline-init-plugin/src/main/groovy/com/example/BaselineInitPlugin.groovy

    package com.example

    import org.gradle.api.Plugin
    import org.gradle.api.invocation.Gradle

    class BaselineInitPlugin implements Plugin<Gradle> {

        void apply(Gradle gradle) {
            println("[INIT-PLUGIN] apply() called")

            // Project-time: apply lightweight conventions
            gradle.beforeProject { project ->
                project.repositories.with { repo ->
                    if (repo.isEmpty()) {
                        println("🔧 [INIT-PLUGIN] Adding default repositories to ${project.name}")
                        mavenCentral()
                        google()
                    }
                }
            }
        }
    }

You can publish it to a local Maven repository by running:

    $ ./gradlew :baseline-init-plugin:publishPluginMavenPublicationToMavenRepoInLocalBuildRepository

Here it is applied in an init script of the `app` project:

init.gradle.kts

    import com.example.BaselineInitPlugin

    // This init script loads the baseline init plugin from mavenLocal and applies it to the build.
    println("[INIT-SCRIPT] Loaded (Gradle ${gradle.gradleVersion})")

    initscript {
        repositories {
            maven { url = uri("./baseline-init-plugin/build/repo") }
            mavenCentral()
            gradlePluginPortal()
        }
        // Either coordinates work; the ID form below relies on the classpath JAR containing the descriptor
        dependencies {
            classpath("com.example:baseline-init-plugin:0.1.0")
        }
    }

    // Apply the plugin
    apply<BaselineInitPlugin>()

init.gradle

    // This init script loads the baseline init plugin from mavenLocal and applies it to the build.
    println "[INIT-SCRIPT] Loaded (Gradle ${gradle.gradleVersion})"

    def pluginClass = Class.forName('com.example.BaselineInitPlugin')

    initscript {
        repositories {
            maven { url = uri('./baseline-init-plugin/build/repo') }
            mavenCentral()
            gradlePluginPortal()
        }
        // Either coordinates work; this relies on the classpath JAR containing the plugin descriptor
        dependencies {
            classpath 'com.example:baseline-init-plugin:0.1.0'
        }
    }

    // Apply the plugin
    apply plugin: pluginClass

Then you can run the app with:

    $ ./gradlew :app:build -I init.gradle(.kts)