# Lazy vs Eager Evaluation

version 9.4.0

Understanding when values in your build are computed is crucial for writing fast and reliable build logic. Gradle differentiates between eager and lazy evaluation:

## Eager Evaluation

Values are computed immediately during the configuration phase, before tasks ever run.

Eager evaluation comes with drawbacks:

- Slows down builds — even when tasks aren’t executed.

- Breaks compatibility — with and configuration caching.

Essentially, eager evaluation performs unnecessary work and reduces flexibility.

## Lazy Evaluation

Lazy values are computed on-demand, typically during the execution phase, using Gradle’s Provider API (`Provider<T>` and `Property<T>`).

This approach has key benefits:

1. Deferred resolution — values are only computed when needed.

2. Better performance — avoids unnecessary computation during configuration.

Lazy evaluation enables build features like incremental builds, build caching, and configuration cache compatibility.

## Lazy APIs

Lazy APIs were explicitly designed to avoid configuring tasks that aren’t going to be run, especially in large projects or Android builds where configuration overhead can be significant.

For example, you might use a `String` in your build script, but this value is eagerly evaluated during the configuration phase. Instead, you should use Gradle’s `Property<String>` type, which defers evaluation until it’s needed during task execution.

Another example which is a common pitfall is using `tasks.withType(Test) {}`:

    tasks.withType(Test) {
        // configure all tasks eagerly
    }

This eagerly configures all `Test` tasks, even in builds where those tasks may never run. Instead, use `configureEach`:

    tasks.withType(Test).configureEach {
        // configure only those tasks actually needed
    }

Or:

    tasks.named("test") {
        // configure only if task will be executed
    }

This use of `configureEach` and `tasks.named(…​)` ensures configurations only apply to tasks invoked by the build.