Gradle 9.9.0 Adds Incremental Kotlin DSL Script Compilation, Extends Test Filters to Non-Method Tests and Changes Problems API IDs
Gradle 9.9.0 compiles Kotlin DSL scripts incrementally (Gradle reports 65% faster recompiles in one test), applies test filters to non-method JUnit tests, and changes Problems API IDs.
Editor's Note ·
- Correction:
- The article says the Gradle 9.9.0 release notes give the release date as 2026-11-07, while the GitHub release page carries a 2026-11-06 17:17 UTC timestamp. The release notes actually say "released 2026-11-06", so the two sources agree on November 6, 2026 and there is no date discrepancy between them. (GitHub's API records the release as published at 2026-11-06T17:17:32Z.)
Overview
Gradle 9.9.0 adds incremental compilation of Kotlin DSL scripts, applies test filters to JUnit Platform tests that are not declared as methods, and makes the wrapper task keep customized properties, according to the Gradle 9.9.0 release notes. The same release changes problem IDs in the incubating Problems API, which the upgrade guide lists among the changes that can alter existing builds. The release notes give the release date as 2026-11-07, while the GitHub release page for tag v9.9.0 carries a timestamp of 2026-11-06 17:17 UTC.
Gradle 9.9.0 follows the 9.8.x line; the Herald previously reported that Gradle 9.8.1 patched three high-rated vulnerabilities.
Kotlin DSL scripts compile incrementally
Per the release notes, Kotlin DSL scripts are now compiled using the Kotlin Build Tools API, “making incremental compilation available for build scripts.” When a script has to be recompiled, for example after a signature change in buildSrc or an included build, only the affected parts are compiled again.
The performance figure is Gradle’s own: the release notes say “In one of our performance tests on a large multi-project build, this makes recompiling scripts 65% faster.” They add that “Builds that rarely recompile scripts see no change.”
ADTmag, reviewing the 9.9.0-RC1 candidate released October 30, wrote that “That result applies to script recompilation, rather than the entire application build.”
Test filters reach non-method tests
Some JUnit Platform engines declare tests on something other than a method. The upgrade guide gives two examples: ArchUnit declares rules on fields, and Spek declares scopes. Gradle previously ran such tests whatever filters were in effect. They are now matched by their enclosing class and the name the engine reports, the same way test methods are matched.
The upgrade guide’s example is that gradle test --tests "SomeUnrelatedTest" previously ran every ArchUnit rule in the source set as well and now runs only SomeUnrelatedTest. It advises reviewing --tests arguments, filter blocks and include/exclude patterns in build and CI configuration, because a filtered run may now execute fewer tests than before.
Two limits are stated. The upgrade guide says engines own the reported names and “may change them in any release, including a patch release”, so a pattern naming an individual non-method test can stop matching after an ArchUnit or Spek upgrade without a deprecation warning from Gradle. Tests that an engine registers only during execution, as Kotest does, can still only be selected by their spec class, according to the release notes.
The release notes add that the Test Retry plugin, which uses test filters, previously reran every non-method-based test whenever any test in the task was retried and now reruns only the failed ones.
Wrapper keeps existing properties
When the wrapper task regenerates an existing gradle-wrapper.properties, it now keeps the values already in the file instead of resetting them to defaults. According to the upgrade guide, this covers the distribution type (bin or all), distributionBase, distributionPath, zipStoreBase, zipStorePath, networkTimeout, validateDistributionUrl, retries and retryBackOffMs. Values configured on the task or passed on the command line still take precedence.
The upgrade guide’s example starts from a file with a gradle-9.8.0-all.zip distribution URL and networkTimeout=60000. Running ./gradlew wrapper --gradle-version 9.9.0 previously wrote a -bin.zip URL and networkTimeout=10000; it now writes a -all.zip URL and keeps networkTimeout=60000.
Three consequences are listed in the upgrade guide. A single --no-validate-url run now disables URL validation until the task is run again with --validate-url. An invalid value in the existing file, such as a non-numeric networkTimeout, now fails the task. A wrapper task registered by the user now writes the default networkTimeout, retries and retryBackOffMs when they are not configured. The distributionUrl is regenerated for the requested Gradle version, so a custom host is not preserved; the upgrade guide says to pass --gradle-distribution-url to keep one.
Problems API: predefined groups and changed IDs
The release notes say the incubating Problems API now provides a predefined hierarchy of problem groups, available from the Problems service as problems.groups. There are eleven root groups, each with predefined subgroups; the examples given include Compilation > Java, Dependencies > Declaration, Packaging > Signing, Provisioning > Tools and Toolchains and Gradle > Plugin Validation. On the console, problems now show the chain of groups they belong to, for example “Unused import (in Compilation > Java)”.
The release notes state that “The legacy problem groups are gone, and both the groups and the names of Gradle’s own problem IDs have changed, so Tooling API clients, Build Scans, and any tooling that matches problems by ID need to update.” One example from the upgrade guide: the ID deprecation:buildsrc-script becomes Gradle:Deprecation:BuildSrc script.
The upgrade guide also says the format of the data embedded in the HTML files of the Configuration Cache report and the Problems report has changed in 9.9.0. It says the reports themselves look the same in a browser, and that the embedded data has never been a public API. ADTmag, writing about the candidate, said tools that match identifiers or extract embedded report data may need adjustments.
Other changes
Among other items, the release notes list:
- Windows Terminal 1.6 or later now shows build progress on the taskbar icon, including in WSL shells hosted by Windows Terminal.
- Buildship, the Gradle integration for Eclipse, can now synchronize builds that have Isolated Projects enabled.
- Three incubating
ProviderFactorymethods,absent(),present(value)andpresentIfNotNull(value), for values that are already known. - An incubating
skipWhenSourceIsEmptyproperty on the Sync task; setting it to false makes the task run when its source is empty, so the destination ends up empty too. - Every page of the User Manual is also available as Markdown, and a new chapter, Securing Gradle Builds, covers securing the build tool, repositories and dependencies.
What is not established
The only independent coverage the Herald found is the ADTmag article, which examined the RC1 candidate rather than the stable release and described Gradle 9.8.2 as the latest stable release at the time. Neither the release notes nor ADTmag reports a measurement beyond Gradle’s single performance test for the 65% figure, and ADTmag noted that teams evaluating the candidate would need to measure the effect on their own build workflows.