What does apply(from = "other.gradle.kts") do, and when would you still reach for it today?
answer
- runs another script in current project context
- no compile, no publish
- local path or URL
- no type-safe accessors
- precompiled convention plugin is the modern replacement
basics
~20 sapply(from = ...) applies a script plugin — it runs another build script file in the context of the current project, as if its contents were inlined. It's a simple way to share build logic across scripts.
solid answer
~50 s`apply(from = "gradle/quality.gradle.kts")` applies a **script plugin**: Gradle executes the referenced script against the current `Project`, so any tasks, configuration, or repositories it declares take effect as if written inline. It's the lightest sharing mechanism — no compilation, no publishing, just a file (local path or URL). The downsides are significant: script plugins are evaluated imperatively, get **no type-safe accessors**, don't participate in the configuration cache as cleanly, and can't declare plugin dependencies via `plugins {}`. Modern Gradle steers you toward **precompiled script plugins** (a `.gradle.kts` in `buildSrc`/`build-logic` that becomes a real plugin with an ID) or convention plugins instead. You'd still reach for `apply(from=)` for quick, low-ceremony extraction of repeated config in small builds, or to apply a shared script fetched from a URL — but for anything maintained, precompiled convention plugins are preferred.
code
kotlin · 8 lines// gradle/quality.gradle.kts (a script plugin)
tasks.register("printQuality") {
doLast { println("quality checks configured") }
}
// build.gradle.kts
apply(from = "gradle/quality.gradle.kts")
// the printQuality task now exists on this projectgo deeper
Know apply(from=) runs another .gradle(.kts) file as if inlined into the current project.
Explain its simplicity vs its lack of type-safety/tooling and name precompiled convention plugins as the upgrade.
Discuss configuration-cache and ordering implications and the security risk of remote scripts; justify a migration to build-logic.
Set policy banning ad-hoc/remote script plugins in favor of a versioned build-logic module; reason about supply-chain and maintainability at org scale.
## What a script plugin is A **script plugin** is just another Gradle build script (`.gradle` or `.gradle.kts`) that you apply into the current script's context with: ```kotlin apply(from = "gradle/quality.gradle.kts") ``` When applied, Gradle runs that file's body against the current `Project` (the `this` of the calling script). Tasks it registers, repositories it adds, and extensions it configures all land on the current project. `from` accepts a relative path, absolute path, or even a URL (`apply(from = "https://example.com/shared.gradle")`). ## Why it's the simplest sharing mechanism - **No build step**: it's a plain file, not compiled or published. - **Quick extraction**: move repeated `tasks`/`repositories` config out of many `build.gradle.kts` files into one shared script. ## Why it's discouraged for serious use - **No type-safe accessors**: inside the script plugin you don't get generated accessors for extensions/tasks from `plugins {}` because a script plugin can't use the `plugins {}` DSL meaningfully; you fall back to `configure<>()`/string-based access. - **Imperative, order-sensitive**: it runs wherever you call `apply(from=)`, so ordering bugs are easy. - **Weaker tooling / configuration cache friendliness** compared to precompiled plugins. - **No clean way to declare its own plugin dependencies**. ## The modern alternative: precompiled script plugins Put a file like `build-logic/src/main/kotlin/myproject.quality-conventions.gradle.kts`. Gradle compiles it into a real plugin whose ID is derived from the file name, and you apply it via the type-safe `plugins {}` DSL: ```kotlin plugins { id("myproject.quality-conventions") } ``` This gives you type-safe accessors, proper dependency declaration, and configuration-cache compatibility — everything `apply(from=)` lacks. ## When apply(from=) still earns its keep - Tiny builds where introducing `buildSrc`/`build-logic` is overkill. - Pulling in a shared snippet by URL. - Legacy builds you're maintaining but not yet refactoring. ## Gotcha Paths in `from` resolve relative to the **applying** script's project directory by default. Applying a remote script by URL is a supply-chain risk (arbitrary build code) and should be pinned/avoided.
- What's the modern replacement for apply(from=) script plugins?Precompiled script (convention) plugins in buildSrc or a build-logic included build, applied via the type-safe plugins {} DSL by their derived ID.
- Why don't you get type-safe accessors in an apply(from=) script?Script plugins are evaluated imperatively and can't use the plugins {} DSL to drive accessor generation, so extension/task access falls back to configure<>()/string lookups.
- What's the risk of apply(from = "https://...")?It executes arbitrary build code fetched at build time — a supply-chain/security risk; the content could change or be tampered with.
saying these in an interview costs you the question
- Confusing apply(from=) (script plugin) with apply(plugin=) (binary plugin by ID) — they do different things.
- Recommending apply(from=) URLs for shared corporate logic without acknowledging the security risk.
- Claiming script plugins get the same type-safe accessors as plugins {}.