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.
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.
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.
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.
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.
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.
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
Gradle provides a rich set of error and warning messages to help you understand and resolve problems in your build.
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.
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.
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.
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.
The build init plugin allows users to create a new Gradle build, supporting various types of projects.
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.
--java-version
parameterBy 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
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.
The Wrapper JAR file size was reduced from ~65K to ~45K by eliminating unused code.
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.
Gradle provides rich APIs for plugin authors and build engineers to develop custom build logic.
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.
CopySpec
instances compatible with configuration cache and workersThe 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.
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:
Settings.rootDir
-> Settings.layout.rootDirectory
Settings.settingsDir
-> Settings.layout.settingsDirectory
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.
To mitigate the security risks and avoid integrating compromised dependencies in your project, Gradle supports dependency verification.
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>
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"/>
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'
}
}
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
}
}
Known issues are problems that were discovered post release that are directly related to changes made in this release.
We love getting contributions from the Gradle community. For information on contributing, please see gradle.org/contribute.
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.