We are excited to announce Gradle 9.1.0-20250809021149+0000 (released 2025-08-09).
This release features 1, 2, ... n, and more.
We would like to thank the following community members for their contributions to this release of Gradle: Eng Zer Jun, EunHyunsu, HeeChul Yang, Jendrik Johannes, Johnny Lim, Junho Lee, Kirill Gavrilov, Matthew Haughton, Na Minhyeok, Philip Wedemann, Philipp Schneider, Pradyumna C, r-a-sattarov, Ryszard Perkowski, Sebastian Schuberth, SebastianHeil, Staffan Al-Kadhimi, winfriedgerlach, Xin Wang.
Be sure to check out the public roadmap for insight into what's planned for future releases.
Switch your build to use Gradle 9.1.0-20250809021149+0000 by updating the wrapper in your project:
./gradlew wrapper --gradle-version=9.1.0-20250809021149+0000 && ./gradlew wrapper
See the Gradle 9.x upgrade guide to learn about deprecations, breaking changes, and other considerations when upgrading to Gradle 9.1.0-20250809021149+0000.
For Java, Groovy, Kotlin, and Android compatibility, see the full compatibility notes.
Gradle provides rich APIs for plugin authors and build engineers to develop custom build logic.
It is possible to generate valid deployment descriptors for Jakarta EE 11 by specifying the corresponding version in the deploymentDescriptor instead of having to use a custom descriptor file.
tasks.ear {
deploymentDescriptor { // custom entries for application.xml:
version = "11"
}
}
AttributeContainer.addAllLater()A new method, addAllLater, has been added to the AttributeContainer API. It allows all attributes from one container to be lazily copied into another.
Here’s an example of how it works:
val color = Attribute.of("color", String::class.java)
val shape = Attribute.of("shape", String::class.java)
val foo = configurations.create("foo").attributes
foo.attribute(color, "green")
val bar = configurations.create("bar").attributes
bar.attribute(color, "red")
bar.attribute(shape, "square")
assert(bar.getAttribute(color) == "red") // `color` is originally red
bar.addAllLater(foo)
assert(bar.getAttribute(color) == "green") // `color` gets overwritten
assert(bar.getAttribute(shape) == "square") // `shape` does not
foo.attribute(color, "purple")
bar.getAttribute(color) == "purple" // addAllLater is lazy
bar.attribute(color, "orange")
assert(bar.getAttribute(color) == "orange") // `color` gets overwritten again
assert(bar.getAttribute(shape) == "square") // `shape` remains the same
This API is particularly useful for cases where attributes need to be configured in a deferred or conditional way, such as in plugin development or complex dependency resolution logic.
Gradle.getBuildPath()This release introduces a new method on the Gradle interface called getBuildPath(). It returns the path of the build relative to the root of the build tree:
:.:my-included-build).This is equivalent to what BuildIdentifier.getBuildPath() provides, but it’s now available directly from the Gradle instance, making it easier to determine which build a given project belongs to.
For example, to get the build path for a project:
val project: Project = getProjectInstance()
val buildPath: String = project.gradle.buildPath
This complements existing APIs like Project.path.
compileOnly plugin dependencies in precompiled Kotlin scriptsPreviously, plugins added via a compileOnly dependency could not be applied or configured using precompiled Kotlin script plugins. Precompiled Kotlin script plugins can use type-safe accessors for plugins added via compileOnly dependencies.
For example, the buildSrc/build.gradle.kts file below declares a compileOnly dependency on a third-party plugin:
plugins {
`kotlin-dsl`
}
dependencies {
compileOnly("com.android.tools.build:gradle:x.y.z")
}
A precompiled convention plugin in buildSrc/src/main/kotlin/my-convention-plugin.gradle.kts can now apply the plugin and use type-safe accessors to configure it:
plugins {
id("com.android.application")
}
android {
// Now accessible via type-safe accessor
}
This improvement makes it easier to use and configure third-party plugins in custom build logic.
kotlin-test dependency for Kotlin projectsThe init task generates Kotlin project builds using the org.jetbrains.kotlin:kotlin-test dependency instead of the more specific kotlin-test-junit5. This change allows the test framework variant (e.g., JUnit5, JUnit4, TestNG) to be inferred automatically based on the configured test runner.
For more details, see the Kotlin Gradle Configuration documentation and the kotlin-test API reference.
The AntlrTask class supports a new packageName property for setting the target package of generated code when using Antlr 4. Previously, specifying the -package argument also required manually configuring the output directory to match the package structure.
The new packageName property simplifies this by automatically setting both the -package argument and the correct output directory based on the package.
Setting the -package argument directly is now deprecated and will become an error in Gradle 10.0.0.
tasks.named("generateGrammarSource").configure {
// Set the target package for generated code
packageName = "com.example.generated"
}
This option is only available when using Antlr 4 and will fail if used with earlier versions.
In previous Gradle versions, if the Antlr-generated sources directory was changed, the associated Java source set was not updated automatically. This required manual updates to ensure the source set included the new directory.
With this release, the generated sources directory is now automatically tracked. When the output directory changes, the Java source set is updated accordingly. Additionally, a task dependency is created between the source generation task and the source set, so tasks that consume the source set will correctly depend on Antlr code generation.
MavenPublication.distributionManagement{}You can explicitly declare the distribution repository in the POM when publishing a Maven publication.
For example, to include GitHub Packages as the distribution repository in the generated POM:
plugins {
id("maven-publish")
}
publications.withType<MavenPublication>().configureEach {
pom {
distributionManagement {
repository {
id = "github"
name = "GitHub OWNER Apache Maven Packages"
url = "https://maven.pkg.github.com/OWNER/REPOSITORY"
}
}
}
}
Gradle provides a rich set of error and warning messages to help you understand and resolve problems in your build.
Previously, when a version constraint conflict occurred, Gradle produced a verbose and hard-to-read error message, especially when transitive dependencies were involved.
It also was formatted in a way that was difficult to comprehend, especially when constraints involved in the conflict were added by transitive dependencies:
> Could not resolve org:foo:3.2.
Required by:
root project 'test'
> Cannot find a version of 'org:foo' that satisfies the version constraints:
Dependency path: 'root project :' (conf) --> 'org:bar:2.0' (runtime) --> 'org:foo:3.1'
Constraint path: 'root project :' (conf) --> 'org:platform:1.1' (platform) --> 'org:foo:{strictly 3.1.1; reject 3.1 & 3.2}'
Constraint path: 'root project :' (conf) --> 'org:foo:3.2'
Constraint path: 'root project :' (conf) --> 'org:baz:3.0' (runtime) --> 'org:foo:3.3'
Constraint path: 'root project :' (conf) --> 'org:other:3.0' (runtime) --> 'org:foo:3.3'
This release introduces a cleaner, more focused error message that focuses attention on the conflicting versions required by the constraints involved in the conflict:
> Could not resolve org:foo.
Required by:
root project 'mec0k'
> Component is the target of multiple version constraints with conflicting requirements:
3.1.1 - directly in 'org:platform:1.1' (platform)
3.2
3.3 - transitively via 'org:baz:3.0' (runtime) (1 other path to this version)
The improved error message makes dependency version conflicts much easier to diagnose by:
Additionally, the error message concludes with a suggested dependencyInsight command for further investigation, giving you an actionable next step to explore the conflict in detail.
Gradle offers a new way to visualize task dependencies without executing the build.
Enable it with the --task-graph option:
./gradlew root r2 --task-graph
This will print a tree-style visualization of the task graph for the specified tasks:
Tasks graph for: root r2
+--- :root (org.gradle.api.DefaultTask)
| \--- :middle (org.gradle.api.DefaultTask)
| +--- :leaf1 (org.gradle.api.DefaultTask)
| \--- :leaf2 (org.gradle.api.DefaultTask, disabled)
\--- :root2 (org.gradle.api.DefaultTask)
+--- :leaf1 (*)
|--- other build task :included:fromIncluded (org.gradle.api.DefaultTask)
\--- :leaf4 (org.gradle.api.DefaultTask, finalizer)
\--- :leaf3 (org.gradle.api.DefaultTask)
(*) - details omitted (listed previously)
This feature provides a quick overview of the task graph, helping users understand the dependencies between tasks without running them.
This feature is incubating and may change in future versions.
--dry-run behavior in Composite BuildsGradle correctly respects --dry-run in Composite Builds, ensuring that tasks are not executed during the execution phase of included builds.
Note that tasks from some included builds may still be executed during configuration time, as part of their configuration logic.
This restores expected behavior and makes --dry-run safer for previewing task execution plans across composite builds.
The Project Report has been updated to show the physical locations of projects in the file system, as well as their logical build paths:
------------------------------------------------------------
Root project 'avoidEmptyProjects-do'
------------------------------------------------------------
Location: /usr/jsmith/projects/avoidEmptyProjects-do
Description: Example project to demonstrate Gradle's project hierarchy and locations
Project hierarchy:
Root project 'avoidEmptyProjects-do'
+--- Project ':app'
\--- Project ':my-web-module'
Project locations:
project ':app' - /app
project ':my-web-module' - /subs/web/my-web-module
To see a list of the tasks of a project, run gradle <project-path>:tasks
For example, try running gradle :app:tasks
This helps authors better understand the structure of hierarchical builds that use non-standard project directories.
The command-line interface is the primary way users interact with Gradle. This release introduces several enhancements to improve usability and feedback in the terminal.
When there are more ongoing events than the console can display, the rich console shows a helpful status line indicating how many lines are not currently visible:
> (2 lines not showing)
This makes it easier to understand when output is being truncated due to limited terminal height.

A new value for the --console command line option called colored is available:
./gradlew [...] --console=colored
This mode enables color output for the console while omitting rich features such as progress bars.

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.
Previously, Gradle always used the PKCS12 keystore format for its encryption keystore (used by the Configuration Cache), ignoring the JVM’s default setting.
Starting with this release, Gradle now honors the JVM’s default keystore type, as long as it supports storing symmetric keys. If the default keystore is a known format that only supports asymmetric keys, Gradle will automatically fall back to PKCS12.
Promoted features are features that were incubating in previous versions of Gradle but are now supported and subject to backward compatibility. See the User Manual section on the "Feature Lifecycle" for more information.
The following are the features that have been promoted in this Gradle release.
getDependencyFactory() in ProjectKnown 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 if 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.