skip to content

What is a NamedDomainObjectProvider, how do you obtain one, and how does it keep container access lazy?

level: middleimportance: should knowfreq 38%

answer

  1. lazy handle to one named element
  2. from register(...) or named(name)
  3. configure{}/map don't realize
  4. get() triggers realization
  5. named = lazy, getByName = eager

basics

~10 s

It's a lazy handle to a named element returned by register or named(name). Holding or configuring it (configure { }) doesn't realize the element; only get() does — so wiring stays deferred.

solid answer

~40 s

A `NamedDomainObjectProvider<T>` is the container's configuration-avoidant reference to a single named element. You get one from `register(name)` or by looking up an existing registration with `named(name)` (or `named(name, Type)` for the typed overload). The key property: obtaining the provider, calling `configure { }` on it, or `map`/`flatMap` over it does **not** realize the underlying element — realization happens only when something calls `get()` or otherwise resolves the value (e.g. wiring it into a task input that runs). This lets you reference and partially configure elements that may never be needed without paying their cost. It extends Gradle's `Provider` type, so it composes with `Property` wiring: you can `map` a provider's attribute and feed it into another task's input lazily. Prefer `named` over `getByName` whenever you only need a lazy handle.

code

kotlin · 12 lines
kotlin
val tasksC = project.tasks

// Lazy lookup of an existing registration
val compileJava: TaskProvider<*> = tasksC.named("compileJava")

// Configure without realizing
compileJava.configure { /* runs only if compileJava is realized */ }

// Wire lazily into another task's input
tasks.register("report") {
    inputs.files(compileJava.map { it.outputs.files })
}

go deeper

for a junior

Know it's a lazy reference to a named element returned by register/named.

for a middle

Explain that configure/map keep it lazy and only get() realizes, and that named beats getByName for laziness.

for a senior

Show composing the provider via map/flatMap into Property-based task inputs to preserve end-to-end laziness.

for a principal

Establish provider-based wiring as the standard and treat eager getByName/findByName in plugins as configuration-time debt.

## What it is `NamedDomainObjectProvider<T>` is a subtype of Gradle's `Provider<T>` specialized for container elements. It's a **lazy reference** to exactly one named element, plus a `configure(Action)` method to queue further configuration of that element without realizing it. ## How you get one - `container.register("name") { ... }` returns a provider for the newly registered (not yet realized) element. - `container.named("name")` returns a provider for an element that already exists in the registration set (throws if the name is unknown). - `container.named("name", Type::class.java)` is the typed overload, giving a `NamedDomainObjectProvider<Type>` and validating the type lazily. ## Why it stays lazy The whole point is configuration avoidance. These operations do **not** realize the element: - Holding the provider in a variable. - `provider.configure { ... }` — queues an action that runs when (and if) the element is realized. - `provider.map { it.someProperty }` / `flatMap { ... }` — derives another lazy provider. Realization is triggered by `provider.get()`, `provider.orNull` resolution, or wiring the provider into something that actually executes (a task input/dependency that runs). ## Contrast with eager lookup `container.getByName("name")` and `findByName("name")` both **realize** the element to return the concrete object. So `named(...)` is the lazy lookup, `getByName(...)` is the eager one. In modern plugin code, reach for `named`. ## Composing with Property wiring Because it's a `Provider`, you can wire an element's lazy attribute straight into a task: ```kotlin val envs = objects.domainObjectContainer(Environment::class.java) val dev: NamedDomainObjectProvider<Environment> = envs.register("dev") { url.convention("https://dev.example.com") } // Lazy: deploy is only wired; dev realizes when deploy runs. tasks.register("deployDev", DeployTask::class.java) { target.set(dev.map { it.url.get() }) } // Later configuration without realizing: dev.configure { timeoutSeconds.set(30) } ``` Nothing about `dev` runs unless `deployDev` is part of the executed task graph — that's the laziness payoff.

  • Does calling configure { } on a NamedDomainObjectProvider realize the element?
    No. configure queues an action that runs only when the element is later realized; it preserves laziness. Only get()/value resolution forces realization.
  • What's the difference between named(name) and getByName(name)?
    named returns a lazy NamedDomainObjectProvider without realizing the element; getByName realizes the element immediately and returns the concrete object.

saying these in an interview costs you the question

  • Saying named(...) realizes the element — it returns a lazy provider.
  • Claiming you must call get() to configure an element — provider.configure{} works lazily.

context