skip to content

What's the difference between pluginManager.withPlugin("java") { } and plugins.withType<JavaPlugin> { }, and when would you pick one over the other?

level: seniorimportance: should knowfreq 45%

answer

  1. withPlugin = id string
  2. withType = plugin class
  3. withType gives the instance
  4. withPlugin works off-classpath
  5. withType is refactor-safe

basics

~20 s

withPlugin keys off the plugin's id string; withType keys off its class. Use withPlugin for third-party plugins not on your classpath; use withType when you have the plugin type and want a typed, refactor-safe reference.

solid answer

~40 s

Both react when a plugin is applied, but they identify the plugin differently. `pluginManager.withPlugin("java")` matches by **plugin id**, so it works even when the plugin's class isn't on your buildscript classpath — ideal for reacting to arbitrary third-party plugins. Its callback receives an `AppliedPlugin` (id metadata), not the plugin instance. `plugins.withType<JavaPlugin>()` matches by **plugin type**, requires that type to be resolvable on your classpath, and hands you the actual `Plugin` instance — which is type-safe and survives id renames. In a convention plugin reacting to well-known core plugins whose types you already depend on (e.g. `JavaPlugin`, `KotlinPluginWrapper`), `withType` reads cleanly. When reacting to a plugin you only know by id, or whose type you deliberately don't want to add to your classpath, `withPlugin` is the right tool. Both run immediately-or-later and avoid apply-ordering assumptions.

code

kotlin · 11 lines
kotlin
// By type: refactor-safe, gives the JavaPlugin instance, type on classpath
plugins.withType<JavaPlugin> {
    extensions.configure<JavaPluginExtension> {
        withSourcesJar()
    }
}

// By id: works even if the plugin class isn't on our classpath
pluginManager.withPlugin("com.github.johnrengelman.shadow") {
    logger.lifecycle("Shadow detected — wiring fat-jar conventions")
}

go deeper

for a junior

Know that one matches by id string and the other by class; details optional.

for a middle

Explain the classpath implication and what each callback receives.

for a senior

Articulate the trade-off (type safety vs. off-classpath reach) and pick correctly per scenario.

for a principal

Use the distinction to design plugin classpath boundaries — keeping optional integrations id-based to avoid coupling the build platform to third-party plugin versions.

## Two ways to identify a plugin Gradle lets you react to plugin application via two complementary APIs that differ only in **how the plugin is matched**. ### withPlugin — match by id ```kotlin pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { appliedPlugin -> // appliedPlugin: AppliedPlugin — gives you id, namespace, name } ``` - Keyed by the **plugin id string** (the same id you'd put in the `plugins {}` block). - Works even if the plugin's implementation class is **not on your buildscript classpath**. You only need to know the id. - The callback receives an `AppliedPlugin`, which exposes id metadata — *not* the plugin object itself. - Best for reacting to **third-party or unknown plugins**, or when you intentionally keep a plugin off your compile classpath. ### withType — match by class ```kotlin plugins.withType<JavaPlugin> { // receiver/argument is the JavaPlugin instance } ``` - Keyed by the **plugin type** (`Class<? extends Plugin>`). - Requires the type to be **resolvable on the classpath** at the point you reference it. - The callback receives the **actual `Plugin` instance**. - **Refactor-safe and type-checked**: a typo is a compile error, and an id rename in the target plugin doesn't break you (you bind to the class). - Best when you already depend on the plugin's type — typically **core plugins** like `JavaPlugin`, `JavaLibraryPlugin`, `ApplicationPlugin`. ## Both share the reaction semantics Regardless of which you use, the action runs **immediately if the plugin is already applied, later if it gets applied, and never otherwise**. So both eliminate apply-order coupling. ## Choosing | Situation | Prefer | |---|---| | Plugin type is on your classpath (core plugins) | `withType` — typed, refactor-safe | | You only know the id / type not on classpath | `withPlugin` | | Reacting to arbitrary third-party plugins | `withPlugin` | | You need the plugin instance | `withType` | | You need id/namespace metadata | `withPlugin` (AppliedPlugin) | ## A subtlety with core plugins Many core plugins are applied by an id that maps to a class, e.g. id `"java"` → `JavaPlugin`. `withType<JavaPlugin>` and `withPlugin("java")` will both fire for it. They are not mutually exclusive — pick based on whether you want the typed instance (withType) or only an id-based match without a classpath dependency (withPlugin).

  • What object does each callback receive?
    withType gives the actual Plugin instance (e.g. JavaPlugin). withPlugin gives an AppliedPlugin holding id/namespace metadata, not the plugin object.
  • Why might you deliberately avoid putting a plugin's type on your classpath and use withPlugin instead?
    To avoid a hard dependency (classpath bloat or version coupling) on a plugin you only need to detect by id, e.g. an optional third-party plugin.

saying these in an interview costs you the question

  • Claiming withType works without the plugin type on the classpath — it can't resolve the class.
  • Saying withPlugin hands you the plugin instance — it gives an AppliedPlugin metadata object instead.

context