skip to content

When configuring an existing task, why use tasks.named over tasks.getByName?

level: middleimportance: should knowfreq 45%

answer

  1. getByName = locate + realize
  2. named = provider, no realize
  3. config block deferred
  4. both validate name eagerly
  5. typed named<Test>

basics

~10 s

tasks.getByName realizes the task right away. tasks.named returns a TaskProvider and defers configuration until the task is actually realized, preserving configuration avoidance.

solid answer

~40 s

`tasks.getByName("test")` locates *and realizes* the task immediately, returning the concrete `Task`. `tasks.named("test")` returns a `TaskProvider<Task>` without realizing anything; `tasks.named("test") { ... }` registers configuration that runs only when (and if) the task is realized. So if you tweak the `test` task with `named` but the current invocation never needs `test`, no realization happens. `named` also fails fast at configuration time if the task name doesn't exist, just like `getByName`, so you don't lose that safety. In Kotlin DSL you can type it: `tasks.named<Test>("test") { ... }`. The rule: locate-and-configure existing tasks with `named`, reserve `getByName` for the rare case where you genuinely need the realized object immediately (and even then, prefer mapping a provider).

code

kotlin · 8 lines
kotlin
// Eager: realizes 'test' on every build, even ./gradlew help
tasks.getByName("test") { /* configure */ }

// Lazy: configuration runs only if 'test' is realized
tasks.named<Test>("test") {
    useJUnitPlatform()
    maxParallelForks = 2
}

go deeper

for a junior

Know named returns a provider and getByName returns the realized task.

for a middle

Explain that named defers realization/config while still validating the name, and use the typed overload.

for a senior

Note when getByName is genuinely justified and how to map providers instead of realizing.

for a principal

Standardize named-over-getByName in shared plugins to keep monorepo configuration time bounded.

## getByName: eager locate `tasks.getByName(name)` does two things at once: it finds the task and **realizes** it, handing you the live `Task`. Any configuration you do runs immediately, at configuration time, whether or not the task is part of the build. In a convention plugin this is a classic source of avoidable configuration cost. ## named: lazy locate `tasks.named(name)` returns a `TaskProvider` and realizes **nothing**. Two forms: ```kotlin val testProvider = tasks.named("test") // just a handle tasks.named("test") { /* config */ } // lazy configuration tasks.named<Test>("test") { useJUnitPlatform() } // typed, Kotlin DSL ``` The configuration block executes only when the task is realized — e.g. when you run it, or when a realized task depends on it. ## Both validate the name eagerly A common worry: "does named hide typos?" No. `named` validates that a task with that name exists at the time of the call and throws `UnknownTaskException` if not — same fail-fast guarantee as `getByName`. What's deferred is the *configuration block* and *realization*, not the existence check. ## Typed lookups and type safety `tasks.named<Test>("test")` (Kotlin) / `tasks.named("test", Test::class)` gives you a typed `TaskProvider<Test>`, so the configuration block sees `Test`-specific properties. With `getByName` you'd cast. ## Putting it together ```kotlin // Eager — realizes 'jar' even for ./gradlew help tasks.getByName("jar") { /* ... */ } // Lazy — 'jar' realized only if needed tasks.named("jar") { /* ... */ } ``` Pair `named` with `dependsOn(provider)` and `configureEach` to keep the whole configuration lazy.

  • Does tasks.named hide typos in task names until later?
    No. named checks that the task exists at call time and throws UnknownTaskException immediately if it doesn't — same fail-fast as getByName. Only the configuration block and realization are deferred, not the existence check.
  • How do you get type-safe access to a Test-specific property via named?
    Use the typed overload: tasks.named<Test>("test") { ... } in Kotlin DSL, or tasks.named("test", Test::class). The provider is TaskProvider<Test>, so the block exposes Test properties without casting.

saying these in an interview costs you the question

  • Claiming named defers the existence check and so hides typos — it validates eagerly.
  • Defaulting to getByName everywhere out of habit, defeating avoidance.

context