What is a Gradle extension, and how does adding one give a plugin its own configuration block in the build script?
answer
- extensions.create(name, Type)
- Project is ExtensionAware
- name in script == registered name
- ExtensionContainer holds instances
- replaces Convention
basics
~10 sAn extension is an object a plugin registers via project.extensions.create("name", Type::class.java). Gradle then exposes a build-script block named after it (e.g. name { ... }) that configures that object.
solid answer
~40 sA Gradle **extension** is a plain object a plugin attaches to the project so users can configure the plugin. The plugin calls `project.extensions.create("greeting", GreetingExtension::class.java)`. Because `Project` is `ExtensionAware`, Gradle registers the object under that name in the project's `ExtensionContainer` and, crucially, generates a build-script DSL block: a method/property named `greeting` that takes a configuration closure/Action. So in the script you write `greeting { message = "hi" }`, which is just calling the configuration action against that extension instance. The extension holds the settings; the plugin's tasks read them later (ideally lazily via `Property`). This is the standard, non-deprecated way to add DSL — it replaced the old `Convention` mechanism. Extensions are also `ExtensionAware` themselves, which is what lets you nest blocks.
code
kotlin · 14 linesabstract class GreetingExtension {
abstract val message: Property<String>
}
class GreetingPlugin : Plugin<Project> {
override fun apply(project: Project) {
val ext = project.extensions.create("greeting", GreetingExtension::class.java)
project.tasks.register("hello") {
doLast { println(ext.message.get()) }
}
}
}
// build.gradle.kts:
// greeting { message = "hi" }go deeper
Know that extensions.create(name, Type) adds a configuration block named 'name' and that Project is ExtensionAware.
Explain the ExtensionContainer, that the registered string is the DSL name, and that the plugin reads values from the kept reference (lazily).
Discuss why typed extensions beat ad-hoc properties (completion, contract), lazy reads, and that this replaces Convention.
Frame extensions as the stable public API surface of a plugin and the governance implications of naming/backward compatibility.
## What an extension is A Gradle **extension** is an ordinary JVM object that a plugin registers on the project to expose user-facing configuration. It is the bridge between *what the user writes in the build script* and *what the plugin's tasks read*. ## ExtensionAware and the ExtensionContainer Every `Project` implements `ExtensionAware`, which exposes an `ExtensionContainer` via `project.extensions`. Plugins add objects to it: ```kotlin project.extensions.create("greeting", GreetingExtension::class.java) ``` The first argument is the **public name**. That name becomes the build-script identifier. When Gradle compiles the script it sees `greeting { ... }` and resolves it to a dynamically-added method that runs the closure/`Action` against the registered `GreetingExtension` instance. ## How the DSL block appears There is no special syntax in the script for "this is an extension". `greeting { ... }` is the same shape as any other Gradle config block; Gradle's dynamic-object machinery routes it to the extension you registered under that name. That is why the *registered name* — not the class name — is what users type. ```kotlin // plugin abstract class GreetingExtension { abstract val message: Property<String> } class GreetingPlugin : Plugin<Project> { override fun apply(project: Project) { val ext = project.extensions.create("greeting", GreetingExtension::class.java) project.tasks.register("hello") { doLast { println(ext.message.get()) } } } } ``` ```kotlin // build.gradle.kts consuming it greeting { message = "Hello from the extension" } ``` ## Why a class, not just variables Using a typed extension object gives users IDE completion, type safety, and a clear public contract. The plugin keeps a reference to the instance so its tasks can read the values during execution. Modeling those values as `Property<T>` (lazy) lets users set them anywhere in the script regardless of evaluation order. ## Relationship to Convention Before extensions, plugins mixed configuration into a `Convention` object. That API is deprecated/removed in modern Gradle; `extensions.create()` is the supported replacement.
- What determines the name of the DSL block users type in the build script?The first argument to extensions.create() — the registered name in the ExtensionContainer — not the extension class's name.
- Why does the plugin keep the reference returned by create()?So its tasks can read the configured values later. Reading via Property defers the read to execution time and avoids ordering problems.
The extension is a settings form the plugin pins to the project; the build-script block is just the place where the user fills that form in.
saying these in an interview costs you the question
- Thinking the block name comes from the class name rather than the registered string.
- Claiming extensions are still configured through Convention.
- Reading extension values eagerly during apply() instead of lazily at execution.