# Writing Plugins

version 8.10.2

If Gradle or the Gradle community does not offer the specific capabilities your project needs, creating your own plugin could be a solution.

Additionally, if you find yourself duplicating build logic across subprojects and need a better way to organize it, custom plugins can help.

## Custom plugin

A plugin is any class that implements the `Plugin` interface.

To create a "hello world" plugin:

    import org.gradle.api.Plugin
    import org.gradle.api.Project

    abstract class SamplePlugin : Plugin<Project> { (1)
        override fun apply(project: Project) {      (2)
            project.tasks.create("SampleTask") {
                println("Hello world!")
            }
        }
    }

1 | Extend the `org.gradle.api.Plugin` interface.
2 | Override the `apply` method.

### 1. Extend the `org.gradle.api.Plugin` interface

Create a class that extends the `Plugin` interface.

    abstract class MyCreateFilePlugin : Plugin<Project> {
        override fun apply() {}
    }

### 2. Override the `apply` method

Add tasks and other logic in the `apply()` method.

When `SamplePlugin` is applied in your project, Gradle calls the `fun apply() {}` method defined. This adds the `SampleTask` to your project.

You can then apply the plugin in your build script:

build.gradle.kts

    import org.gradle.api.Plugin
    import org.gradle.api.Project

    plugins {
        application
    }

    //
    // More build script logic
    //

    abstract class SamplePlugin : Plugin<Project> {
        override fun apply(project: Project) {
            project.tasks.register("createFileTask") {
                val fileText = "HELLO FROM MY PLUGIN"
                val myFile = File("myfile.txt")
                myFile.createNewFile()
                myFile.writeText(fileText)
            }
        }
    }

    apply<SamplePlugin>()   (1)

1 | Apply the `SamplePlugin`.

Note that this is a simple hello-world example and does not reflect best practices.

| Script plugins are not recommended. Plugin code should not be in your `build.gradle(.kts)` file.

Plugins should always be written as pre-compiled script plugins, convention plugins or binary plugins.

## Pre-compiled script plugin

Pre-compiled script plugins offer an easy way to rapidly prototype and experiment. They let you package build logic as `*.gradle(.kts)` script files using the Groovy or Kotlin DSL. These scripts reside in specific directories, such as `src/main/groovy` or `src/main/kotlin`.

To apply one, simply use its `ID` derived from the script filename (without `.gradle`). You can think of the file itself as the plugin, so you do not need to subclass the `Plugin` interface in a precompiled script.

Let’s take a look at an example with the following structure:

    └── buildSrc
        ├── build.gradle.kts
        └── src
           └── main
              └── kotlin
                 └── my-create-file-plugin.gradle.kts

Our `my-create-file-plugin.gradle.kts` file contains the following code:

buildSrc/src/main/kotlin/my-create-file-plugin.gradle.kts

    abstract class CreateFileTask : DefaultTask() {
        @get:Input
        abstract val fileText: Property<String>

        @Input
        val fileName = "myfile.txt"

        @OutputFile
        val myFile: File = File(fileName)

        @TaskAction
        fun action() {
            myFile.createNewFile()
            myFile.writeText(fileText.get())
        }
    }

    tasks.register("createFileTask", CreateFileTask::class) {
        group = "from my plugin"
        description = "Create myfile.txt in the current directory"
        fileText.set("HELLO FROM MY PLUGIN")
    }

And the `buildSrc` build file contains the following:

buildSrc/build.gradle.kts

    plugins {
        `kotlin-dsl`
    }

The pre-compiled script can now be applied in the `build.gradle(.kts`) file of any subproject:

    plugins {
        id("my-create-file-plugin")  // Apply the plugin
    }

The `createFileTask` task from the plugin is now available in your subproject.

## Convention Plugins

Convention plugins are a way to encapsulate and reuse common build logic in Gradle. They allow you to define a set of conventions for a project, and then apply those conventions to other projects or modules.

The example above has been re-written as a convention plugin as a Kotlin script called `MyConventionPlugin.kt` and stored in `buildSrc`:

buildSrc/src/main/kotlin/MyConventionPlugin.kt

    import org.gradle.api.DefaultTask
    import org.gradle.api.Plugin
    import org.gradle.api.Project
    import org.gradle.api.provider.Property
    import org.gradle.api.tasks.Input
    import org.gradle.api.tasks.OutputFile
    import org.gradle.api.tasks.TaskAction
    import java.io.File

    abstract class CreateFileTask : DefaultTask() {
        @get:Input
        abstract val fileText: Property<String>

        @Input
        val fileName = project.rootDir.toString() + "/myfile.txt"

        @OutputFile
        val myFile: File = File(fileName)

        @TaskAction
        fun action() {
            myFile.createNewFile()
            myFile.writeText(fileText.get())
        }
    }

    class MyConventionPlugin : Plugin<Project> {
        override fun apply(project: Project) {
            project.tasks.register("createFileTask", CreateFileTask::class.java) {
                group = "from my plugin"
                description = "Create myfile.txt in the current directory"
                fileText.set("HELLO FROM MY PLUGIN")
            }
        }
    }

The plugin can be given an `id` using a `gradlePlugin{}` block so that it can be referenced in the root:

buildSrc/build.gradle.kts

    gradlePlugin {
        plugins {
            create("my-convention-plugin") {
                id = "my-convention-plugin"
                implementationClass = "MyConventionPlugin"
            }
        }
    }

The `gradlePlugin{}` block defines the plugins being built by the project. With the newly created `id`, the plugin can be applied in other build scripts accordingly:

build.gradle.kts

    plugins {
        application
        id("my-convention-plugin") // Apply the plugin
    }

## Binary Plugins

A binary plugin is a plugin that is implemented in a compiled language and is packaged as a JAR file. It is resolved as a dependency rather than compiled from source.

For most use cases, convention plugins must be updated infrequently. Having each developer execute the plugin build as part of their development process is wasteful, and we can instead distribute them as binary dependencies.

There are two ways to update the convention plugin in the example above into a binary plugin.

1. Use composite builds:

   settings.gradle.kts

       includeBuild("my-plugin")

2. Publish the plugin to a repository:

   build.gradle.kts

       plugins {
           id("com.gradle.plugin.myconventionplugin") version "1.0.0"
       }

Consult the Developing Plugins chapter to learn more.