How does configureEach differ from all{} and forEach on a NamedDomainObjectContainer, and why does the distinction matter for configuration avoidance?
answer
- configureEach = lazy per-element
- all{} = eager, realizes everything
- forEach = eager iteration
- applies to current + future elements
- withType(...).configureEach = lazy typed
basics
~10 sconfigureEach registers a lazy action that runs per element only when each is realized, so it doesn't force creation. all{} and forEach are eager — they realize every element immediately, defeating configuration avoidance.
solid answer
~50 s`configureEach { }` registers a deferred action applied to each element — current and future — but **only when that element is actually realized**. It never forces realization itself, so registered-but-unused elements stay lazy. `all { }` looks deceptively similar but is **eager**: it immediately realizes every existing element and forces realization of any future one the moment it's added, running every configuration closure whether or not the element is needed. `forEach` is plain Kotlin/Groovy iteration over the live collection, which realizes everything to iterate. For configuration avoidance you want `configureEach`: combined with `register`, it means a build that declares 50 environments but uses 2 only ever pays for those 2. Use `withType(T::class) { }` plus `configureEach` for type-filtered lazy bulk config; reserve `all`/`forEach` for the rare case where you genuinely must touch every element now.
code
kotlin · 9 linesval envs = objects.domainObjectContainer(Environment::class.java)
envs.register("dev") { /* ... */ }
envs.register("prod") { /* ... */ }
// Lazy: body runs per env only when that env is realized
envs.configureEach { region.convention("eu-west-1") }
// Eager anti-pattern — forces dev AND prod to realize now:
// envs.all { region.set("eu-west-1") }go deeper
Know configureEach applies a setting to every element and is the lazy, preferred form.
Explain that configureEach is lazy and applies to future elements, while all{}/forEach realize everything eagerly.
Tie it to configuration avoidance, realization triggers, and combine withType(...).configureEach for polymorphic containers.
Drive a convention banning eager all{}/forEach in plugin code and measure configuration-time impact across the build.
## The realization question Every bulk operation on a container either **forces realization** of elements or **defers** until they're realized on their own. That single property decides whether you preserve configuration avoidance. ### configureEach { } — lazy, the right default Registers an action that fires once per element, applied at the moment each element is realized (now for already-realized ones, later for ones realized afterward). It does **not** realize anything by itself. So if you `register("a")`, `register("b")`, and only `a` is ever used, the `configureEach` body runs for `a` only. Applies to current *and future* elements. ### all { } — eager, a trap Reads like "configure all," but it eagerly realizes every existing element immediately and force-realizes every future element the instant it's added. Every closure runs. This is the old, pre-configuration-avoidance idiom; in modern code it's almost always a mistake. ### withType(Type) { } — lazy filter The type-filtered cousin. `withType(Foo::class.java).configureEach { }` (or the action overload, which is lazy) applies only to elements of a given subtype, still lazily. Great for polymorphic containers. ### matching { } — live filtered view Returns a filtered live collection by predicate. Pair it with `configureEach`; calling eager terminal ops on it realizes elements. ### forEach — eager iteration Plain language-level iteration. Iterating the collection realizes its elements. Use only when you truly must inspect realized state of everything. ## Why it matters Gradle configures the whole project graph before executing tasks. If a plugin eagerly realizes every container element, every user closure, every nested task registration, and every property wiring runs at configuration time — slowing every build and risking configuration-cache incompatibility. Laziness keeps that cost proportional to what the build actually uses. ```kotlin val tasksLike = objects.domainObjectContainer(Job::class.java) // LAZY: runs per element only when realized tasksLike.configureEach { timeout.set(60) } // LAZY + typed tasksLike.withType(NightlyJob::class.java).configureEach { retries.set(3) } // EAGER: realizes everything now — avoid // tasksLike.all { timeout.set(60) } ``` ## Mental model `register` + `named` + `configureEach` + `withType(...).configureEach` form the lazy quartet. `create`, `all`, `getByName`, `findByName`, and `forEach` are the eager counterparts.
- Does configureEach apply to elements added after the call?Yes — it applies to both current and future elements, firing for each one as it is realized, which is why it composes cleanly with register.
- Why is all{} considered an anti-pattern in modern plugins?It eagerly realizes every element (current and future), running all configuration closures at configuration time and defeating configuration avoidance and the configuration cache.
saying these in an interview costs you the question
- Saying configureEach forces all elements to be created — it only acts on elements as they are realized.
- Treating all{} and configureEach as interchangeable; all{} is eager.