Gradle Release Notes

The Gradle team is excited to announce Gradle 8.6-rc-1.

This release features support for custom encryption keys for the configuration cache as well as more helpful error and warning messages.

Additionally, this release comes with several improvements to build init and to build authoring for build engineers and plugin authors.

We would like to thank the following community members for their contributions to this release of Gradle: Baptiste Decroix, Björn Kautler, Daniel Lacasse, Danny Thomas, Hyeonmin Park, jeffalder, Jendrik Johannes, John Jiang, Kaiyao Ke, Kevin Mark, king-tyler, Marcin Dąbrowski, Marcin Laskowski, Markus Gaisbauer, Mel Arthurs, Ryan Schmitt, Surya K N, Vladislav Golubtsov, Yanshun Li, Andrzej Ressel

Be sure to check out the Public Roadmap for insight into what's planned for future releases.

Table Of Contents

Upgrade instructions

Switch your build to use Gradle 8.6-rc-1 by updating your wrapper:

./gradlew wrapper --gradle-version=8.6-rc-1

See the Gradle 8.x upgrade guide to learn about deprecations, breaking changes and other considerations when upgrading to Gradle 8.6-rc-1.

For Java, Groovy, Kotlin and Android compatibility, see the full compatibility notes.

New features and usability improvements

Configuration cache improvements

The configuration cache improves build time by caching the result of the configuration phase and reusing it for subsequent builds. This feature can significantly improve build performance.

Custom encryption key

The configuration cache is encrypted to mitigate the risk of accidental exposure of sensitive data. By default, Gradle automatically creates and manages the key, storing it in a keystore in the Gradle User Home directory. While convenient, this may be inappropriate in some environments.

You may now provide Gradle with the key used to encrypt cached configuration data via the GRADLE_ENCRYPTION_KEY environment variable.

More details can be found in the configuration cache section of the Gradle User Manual.

Error and warning reporting improvements

Gradle provides a rich set of error and warning messages to help you understand and resolve problems in your build.

Clearer suggested actions in case of dependency locking errors

Dependency locking is a mechanism that ensures reproducible builds when using dynamic dependency versions.

This release improves error messages by separating the error from the possible action to fix the issue in the console output. Errors from invalid lock file format or missing lock state when strict mode is enabled are now displayed as illustrated below:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':dependencies'.
> Could not resolve all dependencies for configuration ':lockedConf'.
   > Invalid lock state for lock file specified in '<project>/lock.file'. Line: '<<<<<<< HEAD'

* Try:
> Verify the lockfile content. For more information on lock file format, please refer to https://docs.gradle.org/8.6-rc-1/userguide/dependency_locking.html#lock_state_location_and_format in the Gradle documentation.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

Better error reporting of circular references in providers

Before this release, evaluating a provider with a cycle in its value assignment would lead to a StackOverflowError. With this release, circular references are properly detected and reported.

For instance, the following code:

def property = objects.property(String)
property.set("some value")

// wrong, self-references only supported via #update()
property.set(property.map { "$it and more" })

println(property.get()) // error when evaluating

Previously failed with a StackOverflowError and limited details:

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred evaluating root project 'test'.
> java.lang.StackOverflowError (no error message)

Starting with this release, you get a more helpful error message indicating the source of the cycle and a list of the providers in the chain that led to it:

FAILURE: Build failed with an exception.

* Where:
Build file '<project>/build.gradle' line: 7

* What went wrong:
A problem occurred evaluating root project 'test'.
> Circular evaluation detected: property(java.lang.String, map(java.lang.String map(<CIRCULAR REFERENCE>) check-type()))
   -> map(java.lang.String map(property(java.lang.String, <CIRCULAR REFERENCE>)) check-type())
   -> map(property(java.lang.String, map(java.lang.String <CIRCULAR REFERENCE> check-type())))
   -> property(java.lang.String, map(java.lang.String map(<CIRCULAR REFERENCE>) check-type()))

Build init improvements

The build init plugin allows users to create a new Gradle build, supporting various types of projects.

Simpler source package handling

You no longer have to answer an interactive question about the source package. Instead, a default value of org.example will be used. You can override it using an existing option --package flag for the init task. Additionally, you can set the default value by adding a new org.gradle.buildinit.source.package property in gradle.properties in the Gradle User Home.

// ~/.gradle/gradle.properties

org.gradle.buildinit.source.package=my.corp.domain

Names of the generated convention plugins now start with buildlogic instead of the package name, making them shorter and cleaner.

Generating without interactive questions

A new --use-defaults option applies default values for options that were not explicitly configured. It also ensures the init command can be completed without interactive user input. This is handy in shell scripts to ensure they do not accidentally hang.

For example, here is how you can generate a Kotlin library without answering any questions:

gradle init --use-defaults --type kotlin-library

Simpler assignment syntax in Kotlin DSL

Projects generated with Kotlin DSL scripts now use simple property assignment syntax with the = operator.

For instance, setting mainClass of an application looks like this:

application {
	mainClass = "org.example.AppKt"
}

Build authoring improvements

Gradle provides rich APIs for plugin authors and build engineers to develop custom build logic.

Lazy name-based filtering of tasks

Previously, filtering tasks by name required using the matching method using the following pattern:

tasks.matching { it.name.contains("pack") }

The problem was that it triggered the creation of the tasks, even when the task was not part of the build execution.

Starting from this release, you can use:

tasks.named { it.contains("pack") }

Using named will not cause the registered tasks to be eagerly created.

This new method is available on all Gradle containers that extend NamedDomainObjectSet.

Allow Providers to be used with dependency capabilities

Gradle supports declaring capabilities for components to better manage dependencies by allowing Gradle to detect and resolve conflicts between dependencies at build time.

Previously, capability methods only accepted inputs with the capability notation:

dependencies {
    implementation("org.foo:bar:1.0") {
        capabilities {
            requireCapability("org.foo:module-variant") // capability notation
        }
    }
}

Providers can now be passed to capability methods ConfigurationPublications#capability(Object), ModuleDependencyCapabilitiesHandler#requireCapability(Object), and CapabilitiesResolution#withCapability(Object, Action). This allows computing the capability coordinates using values that may change after calling these methods, for example:

dependencies {
    implementation("org.foo:bar:1.0") {
        capabilities {
	// Values in the interpolated String below are lazily evaluated, allowing them to be set after this block
            requireCapability(project.provider(() -> "${project.group}:${project.name}-platform:${project.version}"))
        }
    }
}

// Later, the version of the project is set.
// Without the provider above, this change would not be reflected in the capability.
project.version = "1.0.0"

New update() API allows safe self-referencing lazy properties

Lazy configuration delays calculating a property’s value until it is required for the build. This can lead to accidental recursions when assigning property values of an object to itself:

var property = objects.property<String>()
property.set("some value")
property.set(property.map { "$it and more" })

// Circular evaluation detected (or StackOverflowError, before 8.6)
println(property.get()) // "some value and more"

Previously, Gradle did not support circular references when evaluating lazy properties.

Property and ConfigurableFileCollection now provide their respective update(Transformer<...>) methods which allow self-referencing updates safely:

var property = objects.property<String>()
property.set("some value")
property.update { it.map { "$it and more" } }

println(property.get()) // "some value and more"

Refer to the javadoc for Property.update(Transformer<>) and ConfigurableFileCollection.update(Transformer<>) for more details, including limitations.

Fixed issues

Known issues

Known issues are problems that were discovered post release that are directly related to changes made in this release.

External contributions

We love getting contributions from the Gradle community. For information on contributing, please see gradle.org/contribute.

Reporting problems

If you find a problem with this release, please file a bug on GitHub Issues adhering to our issue guidelines. If you're not sure you're encountering a bug, please use the forum.

We hope you will build happiness with Gradle, and we look forward to your feedback via Twitter or on GitHub.