How do you apply plugins in build.gradle.kts using the plugins {} block, and what makes that block special?
answer
- plugins { id("...") version "..." }
- core accessors: java, application
- kotlin("jvm") helper
- resolved early — literals only
- apply false for version-only
basics
~10 sUse the plugins {} block: list plugins by id and version, e.g. id("org.springframework.boot") version "3.x", or use built-in accessors like kotlin("jvm") or java. It applies plugins declaratively at the top of the script.
solid answer
~40 sThe `plugins {}` block is the modern, declarative way to apply plugins. Inside it you write `id("plugin.id") version "x.y.z"` for community plugins, or use shorthand accessors for core plugins like `java`, `application`, or `kotlin("jvm") version "..."`. What makes the block special is that it is **resolved very early**, before the rest of the script is configured, and it must contain only literal declarations — no arbitrary logic, conditionals, or variables. Gradle parses it ahead of compiling the body so it knows which plugins (and thus which type-safe accessors and extensions) to make available. Versions can be centralised in a version catalog (`alias(libs.plugins.spring.boot)`) or the `pluginManagement` block in settings. This is preferred over the legacy `apply(plugin = "...")` because it gives type-safe accessors and better plugin resolution.
code
kotlin · 5 linesplugins {
java
kotlin("jvm") version "2.0.0"
id("org.springframework.boot") version "3.3.0" apply false
}go deeper
Show the basic id(...) version "..." form and a core accessor like java.
Explain early resolution, the literals-only restriction, kotlin("jvm"), and apply false.
Connect early plugin resolution to type-safe accessor generation; discuss version catalogs and pluginManagement.
Standardise plugin/version governance across a multi-module org via catalogs and convention plugins, minimising drift.
## The plugins {} block Plugins add capabilities to a build — the `java` plugin adds compile/test/jar tasks, the `application` plugin adds a `run` task, and so on. The `plugins {}` block is the **declarative** mechanism for applying them in the Kotlin DSL. ### Forms inside the block ```kotlin plugins { java // core plugin, accessor form application // another core plugin kotlin("jvm") version "2.0.0" // kotlin("...") helper id("org.springframework.boot") version "3.3.0" // community plugin by id id("io.spring.dependency-management") // version inherited / from catalog } ``` - `id("...")` — applies a plugin by its published id; `version "..."` pins it. - `kotlin("jvm")` — a helper that expands to `id("org.jetbrains.kotlin.jvm")`. - Bare accessors like `java` / `application` — generated for **core** Gradle plugins. - `apply false` — declares a plugin's version without applying it here (useful in a root script to set versions for subprojects). ### Why the block is special / restricted Gradle evaluates `plugins {}` **before** it compiles and runs the rest of the script. To do that it must be able to read the block statically, so the block accepts only **constant, literal** declarations — you cannot put `if` statements, loops, local variables, or calls to other functions inside it. This early resolution is exactly what lets Gradle generate **type-safe accessors**: once it knows the `application` plugin is applied, it can expose the `application { }` extension with full typing in the IDE. ### Versions and catalogs Versions can live inline, in `settings.gradle.kts`'s `pluginManagement { }`, or in a version catalog: ```kotlin plugins { alias(libs.plugins.spring.boot) } ``` ### Legacy alternative The old `apply(plugin = "java")` (or `buildscript {}` + `apply`) still works for edge cases (e.g. applying a plugin conditionally), but it does **not** yield type-safe accessors and is discouraged for normal use.
- Why can't you put an if-statement inside the plugins {} block?Gradle resolves the block statically and very early, before compiling the script body, so it only accepts literal declarations — no logic, variables, or conditionals.
- What does `apply false` do in a plugins block?It declares (and resolves the version of) the plugin without applying it in the current script, typically in a root build so subprojects can apply it without repeating the version.
- How does plugins {} differ from the legacy apply(plugin = "...")?plugins {} resolves declaratively, enables type-safe accessors, and integrates with plugin resolution; apply(...) is imperative and gives no typed accessors.
saying these in an interview costs you the question
- Putting conditionals or variables inside plugins {} and expecting it to work.
- Confusing apply false (don't apply now) with not declaring the plugin at all.