What are Gradle's extra (ext) properties, and how do you declare and read them in a build script?
answer
- ExtensionAware -> ExtraPropertiesExtension
- ext {} (Groovy) vs by extra (Kotlin)
- dynamic, untyped Map<String,Object>
- typo fails at execution time
- project.ext / project.extra["k"]
basics
~20 sExtra properties are arbitrary user-defined key/value pairs attached to a Gradle object. You set them with ext { key = value } (Groovy) or by extra (Kotlin) and read them back by name later in the script.
solid answer
~40 sEvery Gradle domain object (Project, Task, etc.) implements `ExtensionAware`, which exposes an `ExtraPropertiesExtension` (`ext`). Extra properties are dynamic, untyped key/value pairs you attach at runtime — Gradle has no compile-time knowledge of them. In Groovy you declare them via `ext { myVersion = '1.2' }` and read with `myVersion` or `project.myVersion`. In Kotlin you use a delegate: `val myVersion by extra("1.2")` to declare, and `val myVersion: String by extra` to read in another script. They're useful for sharing ad-hoc values (versions, flags) across a build. Their main weakness is the lack of type safety and the fact that a typo on read fails only at execution time.
code
kotlin · 10 lines// build.gradle.kts
val springVersion by extra("6.1.0")
val enableMetrics by extra(true)
dependencies {
implementation("org.springframework:spring-core:$springVersion")
}
// map-style access also works
project.extra["buildStamp"] = System.currentTimeMillis()go deeper
Know that ext/extra is a key-value bag, how to set it in Groovy (ext {}) and Kotlin (by extra), and that you read it back by name.
Explain the ExtensionAware/ExtraPropertiesExtension backing, the Kotlin delegate semantics, and that misspelled reads fail at execution time.
Contrast ext with typed extensions and gradle.properties, and explain when ext is the right informal tool vs a smell.
Discuss governance: discouraging ad-hoc ext bags across a large build in favour of version catalogs and convention plugins for maintainability.
## What extra properties are Gradle build scripts often need to stash arbitrary values that aren't part of any plugin's model — a shared version string, a feature flag, a computed path. Gradle supports this through **extra properties**. The mechanism rests on two interfaces: - **`ExtensionAware`** — implemented by `Project`, `Task`, `Gradle`, `Settings`, and most domain objects. It means the object carries an `ExtensionContainer`. - **`ExtraPropertiesExtension`** — a special extension, always present, registered under the name `ext`. It is essentially a `Map<String, Object>` you can write to and read from dynamically. So `project.ext` is the project's bag of dynamic properties. ## Declaring and reading — Groovy ```groovy ext { springVersion = '6.1.0' enableMetrics = true } // read anywhere later dependencies { implementation "org.springframework:spring-core:${springVersion}" } ``` Reading `springVersion` works because Groovy's dynamic dispatch falls through to `ext`. You can be explicit with `project.ext.springVersion` or `project.springVersion`. ## Declaring and reading — Kotlin Kotlin is statically typed, so there is no dynamic fall-through. Gradle provides a **property delegate** named `extra`: ```kotlin val springVersion by extra("6.1.0") // declare + initialise val enableMetrics by extra(true) // read in the same script just use the local val // read in ANOTHER script: val springVersion: String by extra // looks it up by the property name ``` The delegate stores under the property's own name and casts to the declared type on read. `project.extra["springVersion"]` is the map-style equivalent. ## Key characteristics - **Dynamic & untyped** — values are `Any?`. A misspelled key throws `ExtraPropertiesExtension$UnknownPropertyException` only when that line executes. - **Per-object** — `task.ext.foo` is distinct from `project.ext.foo`. - **Not configuration-cache friendly when captured eagerly** — prefer providers for values consumed by tasks. Extra properties are the quick, informal escape hatch; for anything structured, plugins expose typed extensions instead.
- What happens if you read an extra property name that was never set?Gradle throws ExtraPropertiesExtension.UnknownPropertyException at execution time — there is no compile-time check, so a typo surfaces only when that line runs.
- Are extra properties type-safe?No. They are stored as Any?/Object. In Kotlin the by extra delegate casts on read, but a wrong declared type throws ClassCastException at runtime; in Groovy there is no check at all.
saying these in an interview costs you the question
- Claiming ext properties are compile-time type-checked.
- Confusing ext (in-script dynamic) with gradle.properties (file-based).
- Saying you must declare ext in settings.gradle — it lives on any ExtensionAware object.