Gradle Release Notes

The Gradle team is excited to announce Gradle 8.6.

This release features support for custom encryption keys for the configuration cache, several improvements to build init, and updated build authoring APIs.

Additionally, this release provides more helpful error and warning messages and a new API for IDE integrators.

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 by updating your wrapper:

./gradlew wrapper --gradle-version=8.6

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

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.

Build init improvements

The build init plugin allows users to easily 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. The task configuration avoidance API avoids configuring tasks if they are not needed for the execution of a build.

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") }.configureEach {
    // configure details of all '*pack*' tasks that are part of the task graph
}

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

Starting from this release, you can use:

tasks.named { it.contains("pack") }.configureEach {
    // lazily configure details of all '*pack*' tasks that are part of the task graph
}

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 as strings using 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"

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

This release improves error messages in dependency locking 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/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()))

IDE Integration improvements

Gradle is integrated into many IDEs using the Tooling API.

The following improvements are for IDE integrators. They will become available to end-users in future IDE releases once IDE vendors adopt them.

Problems API

The new Problems API has entered a public incubation phase and is ready for integration.

The Problems API enables plugin and build engineers to report rich, structured information about problems that may occur during a build. This information can be received by Tooling API clients, such as IDEs or CI systems, and can be represented in a way that best suits the platform. Tooling API clients are encouraged to begin integrating with the API and provide additional feedback.

Integrating the Problems API

The integration process for established Tooling API clients should be straightforward. Problems can be received using the same ProgressListener interface used for other progress messages. The new template showcases a self-functioning Tooling API client that can receive and present problems. Additionally, a new sample has been introduced to demonstrate various use cases of the API.

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.