Gradle Release Notes

The Gradle team is excited to announce Gradle 8.5.

Gradle now supports running on Java 21.

This release features Kotlin DSL improvements, including faster first use and version catalog support in precompiled Kotlin script plugins.

Additionally, this release comes with more helpful error and warning messages, improvements to build init, dependency verification and several new APIs for build and plugin authors. See the full release notes for details.

We would like to thank the following community members for their contributions to this release of Gradle: Ahmed Ehab, Alex Landau, Aurimas, Björn Kautler, bodhili, Daniel Le Berre, davidburstrom, Franz Wimmer, Jongwoo Han, Ken, Leonardo Silveira, Martin Bonnin, Matthew Von-Maszewski, Nik Clayton, noeppi_noeppi, Philip Wedemann, Philipp Schneider, Tomas Bjerre

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

./gradlew wrapper --gradle-version=8.5

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

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

New features and usability improvements

Full Java 21 support

Gradle 8.4 supported compiling and testing with Java 21 using Java toolchains, but running Gradle itself on Java 21 was not yet supported.

With this release, Gradle now fully supports compiling, testing and running on Java 21.

See the full compatibility documentation for details.

Kotlin DSL improvements

Gradle's Kotlin DSL provides an enhanced editing experience in supported IDEs compared to the traditional Groovy DSL — auto-completion, smart content assist, quick access to documentation, navigation to source, and context-aware refactoring.

Faster first use

When using a Gradle version for the first time, Gradle will start compiling your build logic faster than before.

Previously, there was about four seconds of overhead on powerful machines (and much longer on slower machines) to run a build with Kotlin DSL scripts for the first time. Typically, this happened on every build for ephemeral CI agents, as they have an empty Gradle user home directory. The fact that ephemeral CI agents often have a cold Gradle daemon made this even slower. This is because up to this release Gradle generated a Gradle API Kotlin DSL Extensions JAR before compiling the first .gradle.kts script.

The Kotlin extensions for the Gradle API now ship as part of the Gradle distribution. Consequently, the first use of a Gradle version for compiling .gradle.kts scripts is much faster. This is especially noticeable on ephemeral CI agents or Gradle plugin cross-version tests.

First use of a single project build, running the help task

Version catalog API in precompiled scripts

The versionCatalogs extension accessor is now available in Kotlin DSL precompiled scripts.

It provides an API for accessing version catalogs available on the projects where the precompiled script will be applied. The following example conditionally declares a dependency on a module defined in a version catalog:

// buildSrc/src/main/kotlin/my-convention-plugin.gradle.kts
versionCatalogs                   // This is the extension now available
    .named("libs")                // Assumes there is a libs catalog, throws exception otherwise
    .findLibrary("assertj-core")  // Search the catalog for an assertj-core entry
    .ifPresent { assertjCore ->   // If there is one ... 
        dependencies {            // ... Add a dependency to it 
            testImplementation(assertjCore) 
        }
    }

Check the version catalog API for all supported methods.

Ability to enable Kotlin metadata version check for script compilation

Kotlin/JVM metadata is backward-compatible with all Kotlin releases and forward-compatible with one Kotlin release. For example, Kotlin 1.9 supports Kotlin metadata from Kotlin 1.0 up to Kotlin 2.0, but not from Kotlin 2.1.

The Kotlin compiler checks that the metadata of all dependencies is compatible. Skipping that check is the current default for Gradle script compilation. This may lead to hard-to-troubleshoot errors when libraries built with Kotlin versions unsupported by the Kotlin embedded in Gradle are used in build logic.

Skipping the check will be deprecated soon. Starting with Gradle 9.0, the Kotlin metadata version check will be enabled by default.

To opt-in early to the future-proof behavior, set the org.gradle.kotlin.dsl.skipMetadataVersionCheck property to false. This will enable the metadata check.

To enable the check persistently, set the property in the gradle.properties file of your build root directory:

org.gradle.kotlin.dsl.skipMetadataVersionCheck=false

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 deprecation messages when creating configurations with reserved names

Gradle now provides more helpful messages when you attempt to create a configuration with a "reserved" name prior to Gradle creating it.

Example of deprecation warning:

> Configure project :
The configuration customCompileOnly was created explicitly. This configuration name is reserved for creation by Gradle. This behavior has been deprecated. This behavior is scheduled to be removed in Gradle 9.0. Do not create a configuration with the name customCompileOnly. Consult the upgrading guide for further information: https://docs.gradle.org/8.5/userguide/upgrading_version_8.html#configurations_allowed_usage
When creating configurations during sourceSet custom setup, Gradle found that configuration customCompileOnly already exists with permitted usage(s):
    Consumable - this configuration can be selected by another project as a dependency
    Resolvable - this configuration can be resolved by this project to a set of files
    Declarable - this configuration can have dependencies added to it
Yet Gradle expected to create it with the usage(s):
    Declarable - this configuration can have dependencies added to it
Gradle will mutate the usage of configuration customCompileOnly to match the expected usage. This may cause unexpected behavior. Creating configurations with reserved names has been deprecated. This will fail with an error in Gradle 9.0. Create source set custom prior to creating or accessing the configurations associated with it. For more information, please refer to https://docs.gradle.org/8.5/userguide/building_java_projects.html#sec:implicit_sourceset_configurations in the Gradle documentation.

See authoring maintainable builds to remove these warnings.

Improved handling of wrapped assertion errors when running tests

The way Gradle handles wrapped assertion failures in tests has been significantly improved.

Previously, if a test framework or library wrapped an assertion exception in a more generic exception, the information about the underlying error could not be displayed in the IDE.

As an example, the following code, instead of reporting the underlying assertion error of getting “Actual text” instead of “Expected text”, just returned a blank assertion failed message to listeners.

class TestCase { 
    @Test 
    public void wrappedAssertion() {
        try {
            Assertions.assertEquals("Expected text", "Actual text", "Assertion message");
        } catch (AssertionFailedError ex) {
            // Wrap the actual cause in another AssertionError
            throw new AssertionError("Additional message", ex);
            // Or alternatively in any exception, like RuntimeException
            // throw new RuntimeException(“Additional message”, ex);
        }
    }
}

From now on, thrown exceptions’ causes will be analyzed deeper, and the true underlying assertion errors will be extracted. In the case above, test event listeners will be notified about the fact that a failed comparison was the underlying issue.

These changes will be effective as soon as Gradle 8.5 is used and should not require upgrade of the IDE.

For example, when using Gradle 8.4, the built-in comparison tools won’t be visible in IntelliJ IDEA for the example above.

Error without expected / actual display

As soon as Gradle 8.5 is used, the inner cause will be reported to IntelliJ IDEA, and the familiar comparison tools will immediately appear.

Error with expected / actual display

Better diagnostics when unable to delete files

When Gradle fails to delete files, it will now provide extended diagnostics. This helps troubleshoot issues with locked files, concurrent writes, etc.

The list of files that failed to be deleted is reported. If new files appear under a directory during deletion, their paths will be reported separately. The root cause exceptions for each file deletion failure will also be attached to the stack trace.

Build init improvements

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

Build init utilizing version catalogs

Version catalogs are the recommended way to centrally define dependency modules, plugins, and their versions. Starting from this release, the build init plugin generates projects utilizing version catalogs in the conventional location gradle/libs.versions.toml. This encourages version catalog usage since it became a stable feature in Gradle 8.0.

Refer to the user manual and the TOML file format for information on version catalogs.

New --java-version parameter

By default, the init command enters interactive mode and prompts the user when required information for the selected project type is missing.

To support generating Java projects non-interactively, the --java-version parameter was added to the init task. This parameter allows you to specify the major version of Java to use in the generated project when launching the init task in a non-interactive mode.

  --type java-application \
  --dsl kotlin \
  --test-framework junit-jupiter \
  --package sample.structure \
  --project-name my-gradle-project  \
  --no-split-project  \
  --java-version 17

Wrapper improvements

The recommended way to execute any Gradle build is with the help of the Gradle Wrapper (in short, “Wrapper”). The Wrapper invokes a declared version of Gradle, downloading it beforehand if necessary.

Smaller Wrapper JAR

The Wrapper JAR file size was reduced from ~65K to ~45K by eliminating unused code.

Wrapper JAR LICENSE file

The Wrapper JAR now contains a META-INF/LICENSE file.

This was done to alleviate any doubts regarding the licensing of the Wrapper JAR file. The Wrapper and the Gradle Build Tool are licensed under the Apache Software License 2.0. The JAR file is now self-attributing, so you don't need to add a separate LICENSE file in your codebase.

Build authoring improvements

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

Improvements to Javadoc of generated version catalog accessors

The Javadoc for generated accessors for plugins and libraries from a version catalog now includes information about the version of the plugin or library. This version information can be either a value, a version reference, or the indication that no version was provided.

Version catalog javadoc popup showing library version information

Ability to create CopySpec instances compatible with configuration cache and workers

The FileSystemOperations service now has a copySpec() method for creating CopySpec instances in a configuration cache friendly way. The new method allows you to create, configure, and use CopySpec instances during the execution phase.

For information on service injection for custom Gradle tasks, see the documentation.

Build-wide locations available to Settings scripts and plugins via Settings.layout

Settings scripts and plugins can now access standard build-wide file system locations as lazily computed values via Settings.layout. That is analogous to what Project.layout offers for project-specific locations. These APIs are currently incubating but eventually should replace existing accessors in Settings, which return eagerly computed locations:

Build Features API

The new incubating Build Features API allows plugins to access the status of build features during build time. It is designed to help plugin authors and build engineers adopt Gradle features incrementally.

In the initial release, the API provides information about the Configuration Cache and Isolated Projects features. For each build feature, it is possible to determine whether the user requested it and if it is active in the current build.

Check the BuildFeatures javadoc for more information.

Dependency verification improvements

To mitigate the security risks and avoid integrating compromised dependencies in your project, Gradle supports dependency verification.

Dependency verification Key export format selection

By default, Gradle searches for trusted keys first in the binary .gpg file and then in the ASCII-armored .keys file. Additionally, when Gradle is asked to export all trusted keys via ./gradlew --export-keys, it generates both binary and ASCII-armored versions.

You can now change this behavior to choose only one format. To do so, edit verification-metadata.xml by adding the keyring-format setting:

<?xml version="1.0" encoding="UTF-8"?>
<verification-metadata xmlns="https://schema.gradle.org/dependency-verification"
                   	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   	xsi:schemaLocation="https://schema.gradle.org/dependency-verification https://schema.gradle.org/dependency-verification/dependency-verification-1.3.xsd">
    <configuration>
        <verify-metadata>true</verify-metadata>
        <verify-signatures>true</verify-signatures>
        <keyring-format>armored</keyring-format> <!-- or binary -->
    </configuration>
</verification-metadata>

Dependency verification Key format case sensitivity change

Trusted and ignored keys in verification-metadata.xml are now case-insensitive. By default, they are written in upper-case to match the ASCII-armored format of verification-keyring.keys.

verification-keyring.keys:

pub    ABE9F3126BB741C1

verification-metadata.xml:

<trusted-key id="694621A7227D8D5289699830ABE9F3126BB741C1" group="com.google.guava"/>

Other improvements

Relative path canonicalization

Paths in Copy and Sync tasks are canonicalized so that . is not used and .. only appears at the beginning of a path. In previous versions of Gradle, the absence of this canonicalization could lead to unexpected behaviors, such as missing copies or overwritten files.

task sync(type: Sync) {
    into 'dest'
    into ('.') { // Prior to 8.5, this would not copy anything into dest, with 8.5 it does the copy
        from 'source/dir'
    }
}

Ear plugin

The Ear plugin, which generates Java EE Enterprise Archive (EAR) files, now supports valid deployment descriptors for Java EE 8, Jakarta EE 9, and Jakarta EE 10. You can specify the corresponding version in the deploymentDescriptor instead of having to use a custom descriptor file:

tasks.ear {
    deploymentDescriptor {  // custom entries for application.xml:
        version = "10" // Now supporting version 8, 9, and 10
    }
}

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.