What is a script plugin in Gradle, and how do you apply one?
answer
- plain .gradle.kts file by path/URL
- apply(from = ...) / apply from:
- no plugin ID, no jar
- executes against Project target
- no type-safe accessors
basics
~10 sA script plugin is a plain Gradle script (e.g. other.gradle.kts) holding shared build logic. You apply it with apply(from = "other.gradle.kts") in Kotlin DSL or apply from: 'other.gradle' in Groovy.
solid answer
~40 sA **script plugin** is just an ordinary Gradle build script file containing reusable configuration. Unlike binary plugins (identified by an ID and packaged as a jar), a script plugin is referenced by its file path or URL. You apply it with `apply(from = "versions.gradle.kts")` (Kotlin DSL) or `apply from: 'versions.gradle'` (Groovy DSL). When applied, its statements execute against the applying object — usually the `Project`, so `tasks`, `dependencies`, etc. are in scope. It is the simplest way to share small bits of logic (version constants, a shared task) across modules without publishing a plugin. The trade-off: no `plugins {}` block usage, no type-safe accessors, and it can't itself live in `buildSrc` as a precompiled plugin.
code
kotlin · 8 lines// gradle/shared-config.gradle.kts
repositories { mavenCentral() }
tasks.register("hello") {
doLast { println("shared task from script plugin") }
}
// build.gradle.kts
apply(from = "gradle/shared-config.gradle.kts")go deeper
Know it's a shared .gradle(.kts) file applied with apply(from = ...) and that it runs like a normal build script.
Explain the apply target, the to argument, and the difference from ID-based binary plugins.
Discuss why script plugins lose type-safe accessors and when to graduate to a precompiled/binary plugin.
Frame script plugins as a tactical convenience and set org guidance to prefer convention/precompiled plugins for cross-repo standardization and supply-chain safety.
## What a script plugin is Gradle has two broad plugin flavors: - **Binary (or "precompiled") plugins** — compiled code implementing `Plugin<T>`, identified by a plugin **ID**, applied through the `plugins {}` block. - **Script plugins** — a plain `.gradle` / `.gradle.kts` file you point at by **path or URL**. There is no ID, no jar, no metadata. Applying a script plugin essentially *inlines and executes* that script's body against a target object (the **`apply` target**). By default the target is the `Project` the apply call runs in, so inside the script you can write `dependencies { }`, `tasks.register(...)`, `repositories { }` — exactly as in a normal build file. ## How to apply ```kotlin // build.gradle.kts (Kotlin DSL) apply(from = "gradle/shared-config.gradle.kts") ``` ```groovy // build.gradle (Groovy DSL) apply from: 'gradle/shared-config.gradle' ``` The path is resolved relative to the applying script's project directory. You can also apply from a remote URL: `apply(from = "https://example.com/shared.gradle.kts")` — handy but a supply-chain risk. ## Apply target You can change what the script configures via the `to` argument: ```kotlin subprojects { apply(from = rootProject.file("common.gradle.kts"), to = this) } ``` Here each subproject becomes the target, so the script's `dependencies {}` configures each subproject. ## When to use Script plugins shine for tiny, build-local sharing: a `versions.gradle.kts` holding version constants, or applying the same handful of tasks to several modules. For anything reusable across **repositories** you should publish a binary plugin instead. ## Key limitation preview Because the script is interpreted as a generic build script and not compiled against a known plugin classpath, **type-safe accessors** generated by the `plugins {}` block (e.g. the `application {}` extension accessor) are NOT available inside a script plugin. You fall back to `configure<...>()` / `the<...>()` or string-based lookups.
- Can you apply a script plugin from a remote URL, and why might you avoid it?Yes — apply(from = "https://.../x.gradle.kts"). It's discouraged because it's a supply-chain risk (remote code executed at configuration time), it breaks offline/reproducible builds, and adds network flakiness.
- What object does the script body configure by default?The Project in which apply() is called. You can redirect it with the `to` argument (e.g. apply(from = ..., to = subproject)).
saying these in an interview costs you the question
- Claiming script plugins are applied via the plugins {} block (they are not — that's for ID-based plugins).
- Saying script plugins give type-safe accessors (they don't).