Do Lazy Properties play a key role in the Configuration Cache?

Do Lazy Properties play a key role in the Configuration Cache? Or are they completely orthogonal? Here’s how I would answer the question, but I don’t know if I’m right: Lazy Properties have multiple benefits, not just work avoidance on property level (in contrast to configuration cache that can avoid the entire configuration phase). The Configuration Cache requires reliable task configuration details, so that task properties, dependencies, and build logic are stable, predictable, and serializable. As far as I know, Lazy Properties do help with this:

  • Lazy properties defer work that don’t need to be calculated at configuration time, which optimizes caching by reducing the data needed to be cached.
  • Also they help in ordering problems like the well-known project.afterEvaluate anti-pattern, which we know it does not scale, so they helps with the correctness of configuration caching.
  • I guess lazy properties are also made with serialization in mind, although we know that a Provider can be anything, so for example, Property<URL> is warned by Gradle 8.13 that for reliable serializability it should be something else like Property<URI> (see Dealing with validation problems), but Gradle would warn even if the type was just simply URL, without the lazy property.
  • Lazy property values are finalized after configuration so that they can’t change during execution, this ensures correctness of the task graph, which also helps the correctness of caching.

So am in the right direction or am I wrong? What would be the right explanation? I couldn’t find documentation that clearly explains the question.

Thank you for your response.

I’d say they are quite orthogonal.

Whether your properties are Property or “regular”, at the end of the configuration phase - still within the configuration phase I’d say - the values are calculated and serialized to the configuration cache entry.
The only exception I’m aware of is a Property with a task dependency, those - as they are expected to work with the task output - are only evaluated at execution phase.
Property per-se does not delay work to the execution phase even if it only .get() there like it should be.

The main advantages of Property if used properly are solving the problems of afterEvaluate so that there are no ordering and timing problems or race conditions, and to be able to configure a convention to which a user can go back if he changes his mind by setting to null.