# Part 2: Add an Extension

version 9.7.0-20260528011136+0000

Learn about extensions and how to add them to your plugin to make it configurable.

In this section, you’ll:

- Understand what plugin extensions are and why they are useful.

- Add an extension class to your plugin with configurable properties.

- Register the extension to make it available to users in their build scripts.

## Step 0: Before you Begin

1. You initialized your plugin in part 1.

## Step 1: Understanding Plugin Extensions

A plugin extension is a powerful feature that allows users to configure your plugin using a declarative DSL block in their `build.gradle(.kts)` file. This keeps plugin configuration clean and easy to read.

For example, a user could configure your plugin like this:

    slack {
        token = "..."
        channel = "#builds"
        message = "Build completed!"
    }

Behind the scenes, this `slack {}` block maps directly to a Kotlin or Groovy class with properties. Gradle handles the magic of injecting the values into your plugin’s logic.

## Step 2: Rename the Plugin Class

First, let’s rename our plugin class from the generic "Hello World" example.

Rename the file `plugin/src/main/kotlin/org/example/PluginTutorialPlugin.kt` to `plugin/src/main/kotlin/org/example/SlackPlugin.kt`.

Rename the file `plugin/src/main/groovy/org/example/PluginTutorialPlugin.groovy` to `plugin/src/main/groovy/org/example/SlackPlugin.groovy`.

| Most modern IDEs, like IntelliJ IDEA, can automatically handle both the file and class name updates for you.

Next, we’ll update the class name. The `abstract` keyword is important here because it allows Gradle to use its dependency injection framework to provide the plugin with services it needs, like the `ObjectFactory`.

Change `class PluginTutorialPlugin: Plugin<Project> {}` to `abstract class SlackPlugin: Plugin<Project> {}`.

Change `class PluginTutorialPlugin implements Plugin<Project> {}` to `abstract class SlackPlugin implements Plugin<Project> {}`.

plugin/src/main/kotlin/org/example/SlackPlugin.kt

    abstract class SlackPlugin: Plugin<Project> {
        override fun apply(project: Project) {
            // Register a task
            project.tasks.register("greeting") { task ->
                task.doLast {
                    println("Hello from plugin 'org.example.greeting'")
                }
            }
        }
    }

plugin/src/main/groovy/org/example/SlackPlugin.groovy

    abstract class SlackPlugin implements Plugin<Project> {
        void apply(Project project) {
            // Register a task
            project.tasks.register("greeting") {
                doLast {
                    println("Hello from plugin 'org.example.greeting'")
                }
            }
        }
    }

You’ll also need to update the `build.gradle(.kts)` file to point to the new plugin class name:

plugin/build.gradle.kts

    gradlePlugin {
        // Define the plugin
        plugins {
            create("slack") {
                id = "org.example.slack"
                implementationClass = "org.example.SlackPlugin"
            }
        }
    }

plugin/build.gradle

    gradlePlugin {
        // Define the plugin
        plugins {
            slack {
                id = 'org.example.slack'
                implementationClass = 'org.example.SlackPlugin'
            }
        }
    }

## Step 3: Define the Extension Class

Now, let’s define the class that holds the configurable properties for our plugin. We’ll use Gradle’s `Property<T>` type for these properties, as this makes them configurable lazily and fully compatible with the Configuration Cache.

Declare the extension as an `abstract class` with `abstract` property getters. These are managed properties: Gradle generates the implementation at runtime through class decoration and creates the `Property<T>` instances for you, so there is no need to write a constructor or to inject an `ObjectFactory` manually.

| An extension that carries no custom logic can also be declared as an `interface` with abstract getters. Gradle will fully instantiate it for you in the same way.

Create a new file called `plugin/src/main/kotlin/org/example/SlackExtension.kt` and add the following code:

plugin/src/main/kotlin/org/example/SlackExtension.kt

    package org.example

    import org.gradle.api.provider.Property

    /**
     * The SlackExtension class defines a custom extension for the plugin.
     * This allows users to configure the plugin in their build script via a DSL block, e.g.:
     *
     * slack {
     *     token = "..."
     *     channel = "#general"
     *     message = "Hello from Gradle!"
     * }
     *
     * The `abstract val` declarations are Gradle managed properties: Gradle
     * generates the implementation at runtime through class decoration and
     * creates the `Property<T>` instances automatically. There is no need to
     * declare a constructor or to inject an `ObjectFactory` manually.
     */
    abstract class SlackExtension {

        // The Slack API token used to authenticate requests
        abstract val token: Property<String>

        // The name or ID of the Slack channel to send the message to
        abstract val channel: Property<String>

        // The message content to send to the channel
        abstract val message: Property<String>
    }

plugin/src/main/groovy/org/example/SlackExtension.groovy

    package org.example

    import org.gradle.api.provider.Property

    /**
     * The SlackExtension class defines a custom extension for the plugin.
     * This allows users to configure the plugin in their build script via a DSL block, e.g.:
     *
     * slack {
     *     token = "..."
     *     channel = "#general"
     *     message = "Hello from Gradle!"
     * }
     *
     * The abstract getters are Gradle managed properties: Gradle generates the
     * implementation at runtime through class decoration and creates the
     * `Property<T>` instances automatically. There is no need to declare a
     * constructor or to inject an `ObjectFactory` manually.
     */
    abstract class SlackExtension {

        // The Slack API token used to authenticate requests
        abstract Property<String> getToken()

        // The name or ID of the Slack channel to send the message to
        abstract Property<String> getChannel()

        // The message content to send to the channel
        abstract Property<String> getMessage()
    }

This class will provide the configuration for the `slack` DSL block we saw earlier.

## Step 4: Register the Extension in the Plugin

The final step is to register the `SlackExtension` in our `SlackPlugin` class. This tells Gradle to create the extension and make it available in the build script.

Let’s update the `apply` method to register our new extension and modify the dummy task to use its properties.

plugin/src/main/kotlin/org/example/SlackPlugin.kt

    abstract class SlackPlugin: Plugin<Project> {
        override fun apply(project: Project) {
            // Create the 'slack' extension so users can configure token, channel, and message
            val extension = project.extensions.create("slack", SlackExtension::class.java)

            // Register a task that uses the values from the extension
            project.tasks.register("sendTestSlackMessage") {
                // Use `doLast` to define the action that runs when the task is executed.
                it.doLast {
                    println("${extension.message.get()} to ${extension.channel.get()}")
                }
            }
        }
    }

plugin/src/main/groovy/org/example/SlackPlugin.groovy

    abstract class SlackPlugin implements Plugin<Project> {
        void apply(Project project) {
            // Create the 'slack' extension so users can configure the token, channel, and message.
            def extension = project.extensions.create('slack', SlackExtension)

            // Register a task named 'sendTestSlackMessage'.
            project.tasks.register('sendTestSlackMessage') { task ->
                // Use `doLast` to define the action that runs when the task is executed.
                task.doLast {
                    println "${extension.message.get()} to ${extension.channel.get()}"
                }
            }
        }
    }

After this step, a user can configure your plugin, and the `sendTestSlackMessage` task will use those values when it runs.

Next Step: Create a Custom Task >>