Gradle Release Notes

The Gradle team is excited to announce Gradle 8.7.

Java 22 is now supported for compiling, testing, and running JVM-based projects.

Script compilation for the Groovy DSL can now be avoided thanks to the build cache.

Additionally, this release includes improvements to build authoring, error and warning messages, the configuration cache, and the Kotlin DSL.

See the full release notes below for details.

We would like to thank the following community members for their contributions to this release of Gradle: Aleksandr Postnov, Björn Kautler, Brice Dutheil, Denis Buzmakov, Federico La Penna, Gregor Dschung, Hal Deadman, Hélio Fernandes Sebastião, Ivan Gavrilovic, Jendrik Johannes, Jörgen Andersson, Marie, pandaninjas, Philip Wedemann, Ryan Schmitt, Steffen Yount, Tyler Kinkade, Zed Spencer-Milnes

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

./gradlew wrapper --gradle-version=8.7

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

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

New features and usability improvements

Support for building projects with Java 22

Gradle now supports using Java 22 for compiling, testing, and starting other Java programs. Selecting a language version is done using toolchains.

You cannot run Gradle 8.7 itself with Java 22 because Groovy still needs to support JDK 22. However, future versions are expected to provide this support.

Avoiding Groovy build script compilation thanks to build cache support

The Gradle build cache is a mechanism designed to save time by reusing local or remote outputs from previous builds.

In this release, Groovy build script compilation can benefit from the remote build cache, which, when enabled, reduces initial build times for developers by avoiding this step altogether.

While this feature has been available for Kotlin build script compilation since the introduction of the Kotlin DSL in Gradle 5.0, the Groovy DSL lacked this feature parity.

Build authoring improvements

As a build grows in complexity, it can be challenging to determine when and where particular values are configured. Gradle provides an efficient way to manage this complexity using lazy configuration.

Better API for updating collection properties

This release improves the API for lazy collection properties, a key element of Gradle lazy configuration. Before this release, the interaction of classical collection methods, the concept of convention, and the rules around empty providers have resulted in surprising behaviors for users in some scenarios. Based on the community feedback, this release of Gradle introduces alternative APIs for updating collections with a clearer contract:

The new APIs provide the following benefits:

Conventions are honored

One common complaint was that adding values (using ListProperty.add(...), SetProperty.add(...) or MapProperty.put(...) on top of values from a convention would result in losing the values from the convention.

For example, in an applied plugin, a list property ListProperty<String> is configured with a convention:


In the build file, the build author adds elements to that list property:

// listProp now only contains "two", that’s confusing

However, as explained in the snippet, the behavior is surprising. The newly introduced methods (such as ListProperty.append(...), SetProperty.append(...) and MapProperty.insert(...)) allow the user to express that the convention should be preserved:

// listProp now contains ["one", "two"], as expected
Empty provider values are ignored

Another common source of confusion is how empty providers are handled in collection properties. For instance, adding an empty provider to a collection property using add(...) will cause the entire property to become void of any values as well.

// listProp will be empty if `myEnvVar` is not defined

In order to avoid that behavior, you can instead use the new update APIs introduced in this release (such as ListProperty.append(...), SetProperty.append(...) and MapProperty.insert(...)):

// listProp will still contain "one" if myEnvVar is not defined

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.

Improved plugin application error reporting

When applying a plugin that requires a higher version of Gradle (by specifying the org.gradle.plugin.api-version attribute), the error message when dependency resolution fails will now clearly state the issue:

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring root project 'example'.
> Could not resolve all files for configuration ':classpath'.
   > Could not resolve com.example:plugin:1.0.
     Required by:
         project : > com.example.greeting:com.example.greeting.gradle.plugin:1.0
      > Plugin com.example:plugin:1.0 requires at least Gradle 8.0. This build uses Gradle 7.6.

* Try:
> Upgrade to at least Gradle 8.0. See the instructions at
> Downgrade plugin com.example:plugin:1.0 to an older version compatible with Gradle 7.6.

The failure’s suggested resolutions will include upgrading your version of Gradle or downgrading the version of the plugin. This replaces the previous low-level incompatibility message containing details about all the attributes involved in the plugin request.

Improved copy task error reporting

When including a compressed archive in a Copy task results in duplicate files and DuplicatesStrategy.Fail is used, the error message will now clearly state the issue:

Cannot copy file <SOURCE_FILE> to <DESTINATION_DIR> because file <OTHER_SOURCE_FILE> has already been copied there. 

Suppressable 'dependencies-without-versions' validation error

When generating Gradle Module Metadata files, Gradle prevents your project from publishing broken metadata by looking for common configuration errors.

One of those errors is publishing metadata with dependencies that do not have versions. This validation error can now be suppressed as there are use cases where such metadata is valid:

tasks.withType(GenerateModuleMetadata).configureEach {

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.

Cleaner stack traces in the configuration cache report

The stack traces shown in the configuration cache report for forbidden API calls can be long and contain internal Gradle frames that do not always help to troubleshoot the issue. With this release, internal stack frames are collapsed by default to highlight the build logic that triggered the error:

Collapsed stack frames in the configuration cache report

The collapsed frames can still be expanded and examined if necessary.

Supporting standard streams as task property values

The standard streams (, System.out, and System.err) can now be used as standardInput, standardOutput, and errorOutput of Exec and JavaExec tasks without breaking configuration caching.

User created tasks with properties of types and can also use the standard streams as property values. Setting up custom standard streams with System.setIn, System.setOut, and System.setErr isn't supported.

Kotlin DSL improvements

Embedded Kotlin upgrade to 1.9.22

The embedded Kotlin has been updated from 1.9.10 to Kotlin 1.9.22.

Kotlin DSL Reference update

Javadocs generated from Java code now support a "since" section, indicating the Gradle version when the functionality was introduced.

The information comes from the @since tags in the Javadoc, which haven’t been displayed until now. An example can be found at JavaToolchainSpec.

Other improvements

Generating concise projects with Gradle init

Using the new --no-comments option allows Gradle init to generate new projects that contain code without comments. The resulting build files and source files are smaller and less verbose.

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

You can permanently set this preference by configuring the org.gradle.buildinit.comments property to false in Gradle properties.

Shared build service registration without parameters

Gradle enables tasks to share state or resources, such as pre-computed values or external services, through build services, which are objects holding the state for task use. A build service can optionally take parameters, which Gradle injects into the service instance when creating it.

Shared build services that do not require additional configuration can now be registered without having to provide an empty configuration action using the updated registerIfAbsent() method:

gradle.sharedServices.registerIfAbsent("counter", CountingService, voidAction) 	// Old method
gradle.sharedServices.registerIfAbsent("counter", CountingService)		// New method

Support for TestNG's threadPoolFactoryClass parameter

TestNG is a testing framework supported in Gradle. In TestNG, the threadPoolFactoryClass attribute is used to specify a custom thread pool factory class, which details how TestNG manages threads for parallel test execution.

The threadPoolFactoryClass parameter can now be configured on TestNGOptions for TestNG versions that support it (i.e., TestNG 7.0.0 and above):

testing {
    suites {
        test {
            targets {
                all {
                    testTask.configure {
                        options.threadPoolFactoryClass = "com.example.MyThreadPoolFactory"

An error will occur if this parameter is set for a version of TestNG that does not support it.

Consistent sorting of ignored keys in the metadata verification file

To mitigate the security risks and avoid integrating compromised dependencies in your project, Gradle supports dependency verification. Dependency verification is typically done using checksums or digital signatures. Gradle verifies that downloaded artifacts match the expected checksums or are signed with trusted keys.

Before this release, the ignored keys list in the metadata verification file was not properly sorted by Gradle so that the order would change depending on the execution order, impacting the reproducibility of the build and checksums for the file. In this release, the order is guaranteed to be preserved regardless of the execution order.

Gradle maintains a Virtual File System (VFS) to calculate what needs to be rebuilt on repeat builds of a project. By watching the file system, Gradle keeps the VFS current between builds, reducing the required I/O operations.

This version fixes a problem with detecting content changes indirectly referenced via symlinks, improving the build's correctness.

Support for constraints in JVM test suite dependencies block

The strongly-typed dependencies block introduced in Gradle 7.6 did not support dependency constraints.

In this release, dependency constraints can now be added:

testing {
    suites {
        getByName<JvmTestSuite>("test") {
            dependencies {

Providing separate strings or using named arguments for each part is not supported currently.

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

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.