This chapter provides the information you need to migrate your Gradle 7.x builds to the latest Gradle release. For migrating from Gradle 4.x, 5.x, or 6.x, see the older migration guide first.

We recommend the following steps for all users:

  1. Try running gradle help --scan and view the deprecations view of the generated build scan.

    Deprecations View of a Gradle Build Scan

    This is so that you can see any deprecation warnings that apply to your build.

    Alternatively, you could run gradle help --warning-mode=all to see the deprecations in the console, though it may not report as much detailed information.

  2. Update your plugins.

    Some plugins will break with this new version of Gradle, for example because they use internal APIs that have been removed or changed. The previous step will help you identify potential problems by issuing deprecation warnings when a plugin does try to use a deprecated part of the API.

  3. Run gradle wrapper --gradle-version 7.6 to update the project to 7.6.

  4. Try to run the project and debug any errors using the Troubleshooting Guide.

Upgrading from 7.5 and earlier

The AttributeSchema.setAttributeDisambiguationPrecedence(List) and AttributeSchema.getAttributeDisambiguationPrecedence() methods now accept and return List instead of Collection to better indicate that the order of the elements in those collection is significant.

Strict Kotlin DSL precompiled script plugins accessors generation

Type safe Kotlin DSL accessors generation for precompiled script plugins does not fail the build by default if a plugin requested in such precompiled scripts fails to be applied. Because the cause could be environmental and for backwards compatibility reasons, this behaviour hasn’t changed yet.

Back in Gradle 7.1 the :generatePrecompiledScriptPluginAccessors task responsible for the accessors generation has been marked as non-cacheable by default. The org.gradle.kotlin.dsl.precompiled.accessors.strict system property was introduced in order to offer an opt-in to a stricter mode of operation that fails the build when a plugin application fails, and enable the build cache for that task.

Starting with Gradle 7.6, non-strict accessors generation for Kotlin DSL precompiled script plugins has been deprecated. This will change in Gradle 8.0. Strict accessor generation will become the default. To opt in to the strict behavior, set the 'org.gradle.kotlin.dsl.precompiled.accessors.strict' system property to true.

This can be achieved persistently in the file in your build root directory:

Potential breaking changes

Upgrade to Kotlin 1.7.10

The embedded Kotlin has been updated to Kotlin 1.7.10.

Gradle doesn’t ship with the kotlin-gradle-plugin but the upgrade to 1.7.10 can bring the new version. For example when you use the kotlin-dsl plugin.

The kotlin-gradle-plugin version 1.7.10 changes the type hierarchy of the KotlinCompile task type. It doesn’t extend from AbstractCompile anymore. If you used to select Kotlin compilation tasks by AbstractCompile you need to change that to KotlinCompile.

For example, this


needs to be changed to


In the same vein, if you used to filter tasks by AbstractCompile you won’t obtain the Kotlin compilation tasks anymore:

tasks.withType<AbstractCompile>().configureEach {
    // ...

needs to be changed to

tasks.withType<AbstractCompile>().configureEach {
    // ...
tasks.withType<KotlinCompile>().configureEach {
    // ...

Upgrade to Groovy 3.0.13

Groovy has been updated to Groovy 3.0.13.

Since the previous version was 3.0.11, the 3.0.12 changes are also included.

Upgrade to PMD 6.48.0

PMD has been updated to PMD 6.48.0.

Configuring a non-existing executable now fails

When configuring an executable explicitly for JavaCompile or Test tasks, Gradle will now emit an error if this executable does not exist. In the past, the task would be executed with the default toolchain or JVM running the build.

Changes to dependency declarations in Test Suites

As part of the ongoing effort to evolve Test Suites, dependency declarations in the Test Suites dependencies block are now strongly typed. This will help make this incubating API more discoverable and easier to use in an IDE.

In some cases, this requires syntax changes. For example, build scripts that previously added Test Suite dependencies with the following syntax:

testing {
  suites {
    register<JvmTestSuite>("integrationTest") {
      dependencies {

will now fail to compile, with a message like:

None of the following functions can be called with the arguments supplied:
public operator fun DependencyAdder.invoke(dependencyNotation: CharSequence): Unit defined in org.gradle.kotlin.dsl
public operator fun DependencyAdder.invoke(dependency: Dependency): Unit defined in org.gradle.kotlin.dsl
public operator fun DependencyAdder.invoke(files: FileCollection): Unit defined in org.gradle.kotlin.dsl
public operator fun DependencyAdder.invoke(dependency: Provider<out Dependency>): Unit defined in org.gradle.kotlin.dsl
public operator fun DependencyAdder.invoke(externalModule: ProviderConvertible<out MinimalExternalModuleDependency>): Unit defined in org.gradle.kotlin.dsl

To fix this, replace the reference to project with a call to project():

testing {
  suites {
    register<JvmTestSuite>("integrationTest") {
      dependencies {

Other syntax effected by this change includes:

  • You cannot use Provider<String> as a dependency declaration.

  • You cannot use a Map as a dependency declaration for Kotlin or Java.

  • You cannot use a bundle as a dependency declaration directly (implementation(libs.bundles.testing)). Use implementation.bundle(libs.bundles.testing) instead.

For more information, see the updated declare an additional test suite example in the JVM Test Suite Plugin section of the user guide and the DependencyAdder page in the DSL reference.


Usage of invalid Java toolchain specifications is now deprecated

Along with the Java language version, the Java toolchain DSL allows configuring other criteria such as specific vendors or VM implementations. Starting with Gradle 7.6, toolchain specifications that configure other properties without specifying the language version are considered invalid. Invalid specifications are deprecated and will become build errors in Gradle 8.0.

See more details about toolchain configuration in the user manual.

Deprecated members of the org.gradle.util package now report their deprecation

These members will be removed in Gradle 9.0.

  • ClosureBackedAction

  • CollectionUtils

  • ConfigureUtil

  • DistributionLocator

  • GFileUtils

  • GradleVersion.getBuildTime()

  • GradleVersion.getNextMajor()

  • GradleVersion.getRevision()

  • GradleVersion.isValid()

  • GUtil

  • NameMatcher

  • NameValidator

  • RelativePathUtil

  • TextUtil

  • SingleMessageLogger

  • VersionNumber

  • WrapUtil

Internal DependencyFactory was renamed

The internal org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactory type was renamed to org.gradle.api.internal.artifacts.dsl.dependencies.DependencyFactoryInternal. As an internal type, it should not be used, but for compatibility reasons the inner ClassPathNotation type is still available. This name for the type is deprecated and will be removed in Gradle 8.0. The public API for this is on DependencyHandler, with methods such as localGroovy() providing the same functionality.

Replacement collections in org.gradle.plugins.ide.idea.model.IdeaModule

The testResourcesDirs and testSourcesDirs fields and their getters and setters have been deprecated. Replace usages with the now stable getTestSources() and getTestResources() methods and their respective setters. These new methods return and are backed by ConfigurableFileCollection instances for improved flexibility of use. Gradle now warns upon usage of these deprecated methods. They will be removed in a future version of Gradle.

Replacement methods in org.gradle.api.tasks.testing.TestReport

The getDestinationDir(), setDestinationDir(File), and getTestResultsDirs() and setTestResultsDirs(Iterable) methods have been deprecated. Replace usages with the now stable getDestinationDirectory() and getTestResults() methods and their associated setters. These deprecated elements will be removed in a future version of Gradle.

Deprecated implicit references to outer scope methods in some configuration blocks

Prior to Gradle 7.6, Groovy scripts permitted access to root project configure methods within named container configure methods that throw `MissingMethodException`s. Consider the following snippets for examples of this behavior:

Gradle permits access to the top-level repositories block from within the configurations block when the provided closure is otherwise an invalid configure closure for a Configuration. In this case, the repositories closure executes as if it were called at the script-level, and creates an unconfigured repositories Configuration:

configurations {
    repositories {
    someConf {
        canBeConsumed = false
        canBeResolved = false

The behavior also applies to closures which do not immediately execute. In this case, afterResolve only executes when the resolve task runs. The distributions closure is a valid top-level script closure. But it is an invalid configure closure for a Configuration. This example creates the conf Configuration immediately. During resolve task execution, the distributions block executed as if it were declared at the script-level:

configurations {
    conf.incoming.afterResolve {
        distributions {
            myDist {
                contents {}

task resolve {
    dependsOn configurations.conf
    doFirst {
        configurations.conf.files() // Trigger `afterResolve`

As of Gradle 7.6, this behavior is deprecated. Starting with Gradle 8.0, this behavior will be removed. Instead, Gradle will throw the underlying MissingMethodException. To mitigate this change, consider the following solutions:

configurations {
    conf.incoming.afterResolve {
        // Fully qualify the reference.
        project.distributions {
            myDist {
                contents {}
configurations {

// Extract the script-level closure to the script root scope.
configurations.conf.incoming.afterResolve {
    distributions {
        myDist {
            contents {}

Upgrading from 7.4 and earlier

IncrementalTaskInputs type is deprecated

The IncrementalTaskInputs type was used to implement incremental tasks, that is to say tasks that can be optimized to run on a subset of changed inputs instead of the whole input. This type had a number of drawbacks. In particular using this type it was not possible to determine what input a change was associated with.

You should now use the InputChanges type instead. Please refer to the userguide section about implementing incremental tasks for more details.

Potential breaking changes

Version catalog only accepts a single TOML import file

Only a single file will be accepted when using a from import method. This means that notations, which resolve to multiple files (e.g. the Project.files(java.lang.Object…​) method, when more then one file is passed) will result in a build failure.

Updates to default tool integration versions

Classpath file generated by the eclipse plugin has changed

Project dependencies defined in test configurations get the test=true classpath attribute. All source sets and dependencies defined by the JVM Test Suite plugin are also marked as test code by default. You can now customize test source sets and dependencies via the eclipse plugin DSL:

eclipse {
    classpath {
        testSourceSets = [sourcesSets.test, sourceSets.myTestSourceSet]
        testConfigurations = [configuration.myTestConfiguration]

Alternatively, you can adjust or remove classpath attributes in the eclipse.classpath.file.whenMerged { } block.

Signing plugin defaults to gpg instead of gpg2 when using the GPG command

The signature plugin’s default executable when using the GPG command changed from gpg2 to gpg. The change was motivated as GPG 2.x became stable, and distributions started to migrate by not linking the gpg2 executable.

In order to set the old default, the executable can be manually defined in


mustRunAfter constraints no longer violated by finalizedBy dependencies

In previous Gradle versions, mustRunAfter constraints between regular tasks and finalizer task dependencies would not be honored.

For a concrete example, consider the following task graph definition:

tasks {
    register("dockerTest") {
        dependsOn("dockerUp")     // dependsOn createContainer mustRunAfter removeContainer
        finalizedBy("dockerStop") // dependsOn removeContainer

    register("dockerUp") {

    register("dockerStop") {

    register("createContainer") {

    register("removeContainer") {

The relevant constraints are:

  • dockerStop is a finalizer of dockerTest so it must be run after dockerTest;

  • removeContainer is a dependency of dockerStop so it must be run before dockerStop;

  • createContainer must run after removeContainer;

Prior to Gradle 7.5, gradle dockerTest would yield the following order of execution, in violation of the mustRunAfter constraint between :createContainer and :removeContainer:

> Task :createContainer UP-TO-DATE
> Task :dockerUp UP-TO-DATE
> Task :dockerTest UP-TO-DATE
> Task :removeContainer UP-TO-DATE
> Task :dockerStop UP-TO-DATE

Starting with Gradle 7.5, mustRunAfter constraints are fully honored yielding the following order of execution:

> Task :removeContainer UP-TO-DATE
> Task :createContainer UP-TO-DATE
> Task :dockerUp UP-TO-DATE
> Task :dockerTest UP-TO-DATE
> Task :dockerStop UP-TO-DATE

Scala Zinc version updated to 1.6.1

Zinc is the Scala incremental compiler that allows Gradle to always compile the minimal set of files needed by the current file changes. It takes into account which methods are being used and which have changed, which means it’s much more granular than just interfile dependencies.

Zinc version has been updated to the newest available one in order to benefit from all the recent bugfixes. Due to that, if you use zincVersion setting it’s advised to remove it and only use the default version, because Gradle will only be able to compile Scala code with Zinc versions set to 1.6.x or higher.

Removes implicit --add-opens for test workers

Prior to Gradle 7.5, JDK modules java.base/java.util and java.base/java.lang were automatically opened in test workers on JDK9+ by passing --add-opens CLI arguments. This meant any tests were able to perform deep reflection on JDK internals without warning or failing. This caused tests to be unreliable by allowing code to pass when it would otherwise fail in a production environment.

These implicit arguments have been removed and are no longer added by default. If your code or any of your dependencies are performing deep reflection into JDK internals during test execution, you may see the following behavior changes:

Before Java 16, new build warnings are shown. These new warnings are printed to stderr and will not fail the build:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by$2 (file:/.../testng-5.12.1.jar) to <method>
WARNING: Please consider reporting this to the maintainers of$2
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

With Java 16 or higher, exceptions are thrown that fail the build:

// Thrown by TestNG
java.lang.reflect.InaccessibleObjectException: Unable to make <method> accessible: module java.base does not "opens java.lang" to unnamed module @1e92bd61
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(
	at java.base/java.lang.reflect.Method.setAccessible(

// Thrown by ProjectBuilder
org.gradle.api.GradleException: Could not inject synthetic classes.
	at org.gradle.initialization.DefaultLegacyTypesSupport.injectEmptyInterfacesIntoClassLoader(
	at org.gradle.testfixtures.internal.ProjectBuilderImpl.getGlobalServices(
	at org.gradle.testfixtures.internal.ProjectBuilderImpl.createProject(
Caused by: java.lang.RuntimeException: java.lang.IllegalAccessException: module java.base does not open java.lang to unnamed module @1e92bd61

In most cases, these errors can be resolved by updating the code or dependency performing the illegal access. If the code-under-test or the newest version of the dependency in question performs illegal access by design, the old behavior can be restored by opening the java.base/java.lang and java.base/java.util modules manually with --add-opens:

tasks.withType(Test).configureEach {

If you are developing Gradle plugins, ProjectBuilder relies on reflection in the java.base/java.lang module. Gradle will automatically add the appropriate --add-opens flag to tests when the java-gradle-plugin plugin is applied.

If you are using TestNG, versions prior to 5.14.6 perform illegal reflection. Updating to at least 5.14.6 should fix the incompatibility.

Checkstyle tasks use toolchains and execute in parallel by default

The Checkstyle plugin now uses the Gradle worker API to run Checkstyle as an external worker process, so that multiple Checkstyle tasks may now run in parallel within a project.

Since Checkstyle runs as an external process you can control the memory via the minHeapSize and maxHeapSize properties on the Checkstyle tasks. In case of out of memory errors, increasing the max memory via the maxHeapSize property should solve the issue. By default, the process will start with maxHeapSize of 512MB. We also recommend to update Checkstyle to version 9.3 or later.

Missing files specified with relative paths when running Checkstyle

Gradle 7.5 consistently sets the current working directory for the Checkstyle task to GRADLE_USER_HOME/workers. This may cause problems with custom Checkstyle tasks or Checkstyle configuration files that assume a different directory for relative paths.

Previously, Gradle selected the current working directory based on the directory where you ran Gradle. If you ran Gradle in:

  • the root directory of a project: Gradle uses the root directory as the current working directory.

  • a nested directory of a project: Gradle uses the root directory of the subproject as the current working directory.

In version 7.5 and above, Gradle consistently sets the current working directory for the Checkstyle task to GRADLE_USER_HOME/workers.


Converting files to a classpath where paths contain file separator

Java has the concept of a path separator which is used to separate individual paths in a list of paths, for example in a classpath string. The individual paths must not contain the path separator. Consequently, using @FileCollection.getAsPath() for files with paths that contain a path separator has been deprecated, and it will be an error in Gradle 8.0 and later. Using a file collection with paths which contain a path separator may lead to incorrect builds, since Gradle doesn’t find the files as inputs, or even to build failures when the path containing the path separator is illegal on the operating system.

dependencyInsight --singlepath option is deprecated

For consistency, this was changed to --single-path. The API method has remained the same, this only affects the CLI.

Groovydoc includePrivate property is deprecated

There is a new access property that allows finer control over what is included in the Groovydoc.

Provider-based API must be used to run external processes at the configuration time

Using Project.exec, Project.javaexec, and standard Java and Groovy APIs to run external processes at the configuration time is now deprecated when the configuration cache is enabled. It will be an error in Gradle 8.0 and later. Gradle 7.5 introduces configuration cache-compatible ways to execute and obtain output of an external process with the provider-based APIs or a custom implementation of the ValueSource interface. The configuration cache chapter has more details to help with the migration to the new APIs.

Upgrading from 7.3 and earlier


AdoptOpenJDK toolchain download

Following the move from AdoptOpenJDK to Adoptium, under the Eclipse foundation, it is no longer possible to download an AdoptOpenJDK build from their end point. Instead, an Eclipse Temurin or IBM Semeru build is returned.

Gradle 7.4+ will now emit a deprecation warning when the AdoptOpenJDK vendor is specified in the toolchain specification and it is used by auto provisioning. If you must use AdoptOpenJDK, you should turn off auto-download. If an Eclipse Temurin or IBM Semeru build works for you, specify JvmVendorSpec.ADOPTIUM or JvmVendorSpec.IBM_SEMERU as the vendor or leave the vendor unspecified.

File trees and empty directory handling

When using @SkipWhenEmpty on an input file collection, Gradle skips the task when it determines that the input is empty. If the input file collection consists only of file trees, Gradle ignores directories for the emptiness check. Though when checking for changes to the input file collection, Gradle only ignores directories when the @IgnoreEmptyDirectories annotation is present.

Gradle will now ignore directories for both the @SkipWhenEmpty check and for determining changes consistently. Until Gradle 8.0, Gradle will detect if an input file collection annotated with @SkipWhenEmpty consists only of file trees and then ignore directories automatically. Moreover, Gradle will issue a deprecation warning to advise the user that the behavior will change in Gradle 8.0, and that the input property should be annotated with @IgnoreEmptyDirectories. To ignore directories in Gradle 8.0 and later, the input property needs to be annotated with @IgnoreEmptyDirectories.

Finally, using @InputDirectory implies @IgnoreEmptyDirectories, so no changes are necessary when using this annotation. The same is true for inputs.dir() when registering an input directory via the runtime API.

Using LazyPublishArtifact without a FileResolver is deprecated

When using a LazyPublishArtifact without a FileResolver, a different file resolution strategy is used, which duplicates some logic in the FileResolver. To improve consistency, LazyPublishArtifact should be used with a FileResolver, and will require it in the future.

This also affects other internal APIs that use LazyPublishArtifact, which now also have deprecation warnings where needed.

TAR trees from resources without backing files

It is possible to create TAR trees from arbitrary resources. If the resource is not created via project.resources, then it may not have a backing file. Creating a TAR tree from a resource with no backing file has been deprecated. Instead, convert the resource to a file and use project.tarTree() on the file. To convert the resource to a file you can use a custom task or use dependency management to download the file via a URL. This way, Gradle is able to apply optimizations like up-to-date checks instead of re-running the logic to create the resource every time.

Unique attribute sets

The set of Attributes associated with a consumable configuration within a project, must be unique across all other configurations within that project which share the same set of Capabilitys. This will be checked at the end of configuring variant configurations, as they are locked against further mutation.

If the set of attributes is shared across configurations, consider adding an additional attribute to one of the variants for the sole purpose of disambiguation.

Provider#forUseAtConfigurationTime() has been deprecated

Provider#forUseAtConfigurationTime is now deprecated and scheduled for removal in Gradle 9.0. Clients should simply remove the call.

The call was mandatory on providers of external values such as system properties, environment variables, Gradle properties and file contents meant to be used at configuration time together with the configuration cache feature.

Starting with version 7.4 Gradle will implicitly treat an external value used at configuration time as a configuration cache input.

Clients are also free to use standard Java APIs such as System#getenv to read environment variables, System#getProperty to read system properties as well as Gradle APIs such as Project#property(String) and Project#findProperty(String) to read Gradle properties at configuration time. The Provider based APIs are still the recommended way to connect external values to task inputs for maximum configuration cache reuse.

Task execution listeners and events

The Gradle configuration cache does not support listeners and events that have direct access to Task and Project instances, which allows Gradle to execute tasks in parallel and to store the minimal amount of data in the configuration cache. In order to move towards an API that is consistent whether the configuration cache is enabled or not, the following APIs are deprecated and will be removed or be made an error in Gradle 8.0:

See the configuration cache chapter for details on how to migrate these usages to APIs that are supported by the configuration cache.

Build finished events

Build finished listeners are not supported by the Gradle configuration cache. And so, the following API are deprecated and will be removed in Gradle 8.0:

See the configuration cache chapter for details on how to migrate these usages to APIs that are supported by the configuration cache.

Calling Task.getProject() from a task action

Calling Task.getProject() from a task action at execution time is now deprecated and will be made an error in Gradle 8.0. This method can be used during configuration time, but it is recommended to avoid doing this.

See the configuration cache chapter for details on how to migrate these usages to APIs that are supported by the configuration cache.

Calling Task.getTaskDependencies() from a task action

Calling Task.getTaskDependencies() from a task action at execution time is now deprecated and will be made an error in Gradle 8.0. This method can be used during configuration time, but it is recommended to avoid doing this.

See the configuration cache chapter for details on how to migrate these usages to APIs that are supported by the configuration cache.

Using a build service from a task without the corresponding Task.usesService declaration

Gradle needs the information so it can properly honor the build service lifecycle and its usage constraints.

This will become an error in a future Gradle version.

Check the Shared Build Services documentation for more information.

VersionCatalog and VersionCatalogBuilder deprecations

Some methods in VersionCatalog and VersionCatalogBuilder are now deprecated and scheduled for removal in Gradle 8.0. Specific replacements can be found in the JavaDoc of the affected methods.

These methods were changed to improve the consistency between the libs.versions.toml file and the API classes.

Upgrading from 7.2 and earlier

Potential breaking changes

Updates to bundled Gradle dependencies

Application order of plugins in the plugins block

The order in which plugins in the plugins block were actually applied was inconsistent and depended on how a plugin was added to the class path. Now the plugins are always applied in the same order they are declared in the plugins block which in rare cases might change behavior of existing builds.

Effects of exclusion on substituted dependencies in dependency resolution

Prior to this version, a dependency substitution target could not be excluded from a dependency graph. This was caused by checking for exclusions prior to performing the substitution. Now Gradle will also check for exclusion on the substitution result.

Version catalog

Generated accessors no longer give access to the type unsafe API. You have to use the version catalog extension instead.

Toolchain support in Scala

When using toolchains in Scala, the -target option of the Scala compiler will now be set automatically. This means that using a version of Java that cannot be targeted by a version of Scala will result in an error. Providing this flag in the compiler options will disable this behaviour and allow to use a higher Java version to compile for a lower bytecode target.

Declaring input or output directories which contain unreadable content

For up-to-date checks Gradle relies on tracking the state of the inputs and the outputs of a task. Gradle used to ignore unreadable files in the input or outputs to support certain use-cases, although it cannot track their state. Declaring input or output directories on tasks which contain unreadable content has been deprecated and these use-cases are now supported by declaring the task to be untracked. Use the @UntrackedTask annotation or the Task.doNotTrackState() method to declare a task as untracked.

When you are using a Copy task for copying single files into a directory which contains unreadable files, use the method Task.doNotTrackState().

Upgrading from 7.1 and earlier

Potential breaking changes

Security changes to application start scripts and Gradle wrapper scripts

Due to CVE-2021-32751, gradle, gradlew and start scripts generated by Gradle’s application plugin have been updated to avoid situations where these scripts could be used for arbitrary code execution when an attacker is able to change environment variables.

You can use the latest version of Gradle to generate a gradlew script and use it to execute an older version of Gradle.

This should be transparent for most users; however, there may be changes for Gradle builds that rely on the environment variables JAVA_OPTS or GRADLE_OPTS to pass parameters with complicated quote escaping. Contact us if you suspect something has broken your build and you cannot find a solution.

Updates to bundled Gradle dependencies


Using Java lambdas as task actions

When using a Java lambda to implement a task action, Gradle cannot track the implementation and the task will never be up-to-date or served from the build cache. Since it is easy to add such a task action, using task actions implemented by Java lambdas is now deprecated. See Validation problems for more details how to fix the issue.

Relying on equals for up-to-date checks is deprecated

When a task input is annotated with @Input and is not a type Gradle understand directly (like String), then Gradle uses the serialized form of the input for up-to-date checks and the build cache key. Historically, Gradle also loads the serialized value from the last execution and then uses equals() to compare it to the current value for up-to-date checks. Doing so is error prone, doesn’t work with the build cache and has a performance impact, therefore it has been deprecated. Instead of using @Input on a type Gradle doesn’t understand directly, use @Nested and annotate the properties of the type accordingly.

Upgrading from 7.0 and earlier

Potential breaking changes

The org.gradle.util package is now a public API

Officially, the org.gradle.util package is not part of the public API. But, because this package name doesn’t contain the word internal, many Gradle plugins already consider as one. Gradle 7.1 addresses the situation and marks the package as public. The classes that were unintentionally exposed are either deprecated or removed, depending on their external usage.

The following classes have known usages in external plugins and are now deprecated and set for removal in Gradle 8.0:
  • VersionNumber

  • TextUtil

  • WrapUtil

  • RelativePathUtil

  • DistributionLocator

  • SingleMessageLogger

  • ConfigureUtil

ConfigureUtil is being removed without a replacement. Plugins can avoid the need for using ConfigureUtil by following our example.

The following classes have only internal usages and were moved from org.gradle.util to the org.gradle.util.internal package:
  • Resources

  • RedirectStdOutAndErr

  • Swapper

  • StdInSwapper

  • IncubationLogger

  • RedirectStdIn

  • MultithreadedTestRule

  • DisconnectableInputStream

  • BulkReadInputStream

  • MockExecutor

  • FailsWithMessage

  • FailsWithMessageExtension

  • TreeVisitor

  • AntUtil

  • JarUtil

The last set of classes have no external or internal usages and therefore were deleted:
  • DiffUtil

  • NoopChangeListener

  • EnumWithClassBody

  • AlwaysTrue

  • ReflectionEqualsMatcher

  • DynamicDelegate

  • IncubationLogger

  • NoOpChangeListener

  • DeferredUtil

  • ChangeListener

The return type of source set extensions have changed

The following source sets are contributed via an extension with a custom type:

The 'idiomatic' DSL declaration is backward compatible:

sourceSets {
    main {
        groovy {
            // ...

However, the return type of the groovy block has changed to the extension type. This means that the following snippet no longer works in Gradle 7.1:

 sourceSets {
     main {
         GroovySourceSet sourceSet = groovy {
             // ...

Start scripts require bash shell

The command used to start Gradle, the Gradle wrapper as well as the scripts generated by the application plugin now require bash shell.


Using convention mapping with properties with type Provider is deprecated

Convention mapping is an internal feature that is been replaced by the Provider API. When mixing convention mapping with the Provider API, unexpected behavior can occur. Gradle emits a deprecation warning when a property in a task, extension or other domain object uses convention mapping with the Provider API.

To fix this, the plugin that configures the convention mapping for the task, extension or domain object needs to be changed to use the Provider API only.

JacocoMerge task type is deprecated

The JacocoMerge task was used for merging coverage reports from different subprojects into a single report. The same functionality is also available on the JacocoReport task. Because of the duplication, JacocoMerge is now deprecated and scheduled for removal in Gradle 8.0.

Setting custom build layout

Command line options:

  • -c, --settings-file for specifying a custom settings file location

  • -b, --build-file for specifying a custom build file location

have been deprecated.

Setting custom build file using buildFile property in GradleBuild task has been deprecated.

Please use the dir property instead to specify the root of the nested build. Alternatively, consider using one of the recommended alternatives for GradleBuild task as suggested in Avoid using the GradleBuild task type section.

Setting custom build layout using StartParameter methods setBuildFile(File) and setSettingsFile(File) as well as the counterpart getters getBuildFile() and getSettingsFile() have been deprecated.

Please use standard locations for settings and build files:

  • settings file in the root of the build

  • build file in the root of each subproject

For the use case where custom settings or build files are used to model different behavior (similar to Maven profiles), consider using system properties with conditional logic. For example, given a piece of code in either settings or build file:

if (System.getProperty("profile") == "custom") {
    println("custom profile")
} else {
    println("default profile")

You can pass the profile system property to Gradle using gradle -Dprofile=custom to execute the code in the custom profile branch.

Substitution.with replaced with Substitution.using

Dependency substitutions using with method have been deprecated and are replaced with using method that also allows chaining. For example, a dependency substitution rule substitute(project(':a')).with(project(':b')) should be replaced with substitute(project(':a')).using(project(':b')). With chaining you can, for example, add a reason for a substitution like this: substitute(project(':a')).using(project(':b')).because("a reason").

Properties deprecated in JavaExec task

  • The main getters and setters in JavaExec task have been deprecated. Use the mainClass property instead.

Deprecated properties in compile task

Non-hierarchical project layouts

Gradle 7.1 deprecated project layouts where subprojects were located outside of the project root. However, based on community feedback we decided to roll back in Gradle 7.4 and removed the deprecation. As a consequence, the Settings.includeFlat() method is deprecated in Gradle 7.1, 7.2, and 7.3 only.

Deprecated Upload task

Gradle used to have two ways of publishing artifacts. Now, the situation has been cleared and all build should use the maven-publish plugin. The last remaining artifact of the old way of publishing is the Upload task that has been deprecated and scheduled for removal in Gradle 8.0. Existing clients should migrate to the maven-publish plugin.

Deprecated conventions

The concept of conventions is outdated and superseded by extensions. To reflect this in the Gradle API, the following elements are now deprecated:

The internal usages of conventions have been also cleaned up (see the deprecated items below).

Plugin authors migrate to extensions if they replicate the changes we’ve done internally. Here are some examples:

Deprecated base plugin conventions

The convention properties contributed by the base plugin have been deprecated and scheduled for removal in Gradle 8.0. The conventions are replaced by the base { } configuration block backed by BasePluginExtension.

The old convention object defines the distsDirName, libsDirName and archivesBaseName properties with simple getter and setter methods. Those methods are available in the extension only to maintain backwards compatibility. Build scripts should solely use the properties of type Property:

base {
    archivesName = 'customBase'
    distsDirectory = layout.buildDirectory.dir('custom-dist')
    libsDirectory = layout.buildDirectory.dir('custom-libs')

Deprecated ApplicationPluginConvention

ApplicationPluginConvention was already listed as deprecated in the documentation. Now, it is officially annotated as deprecated and scheduled for removal in Gradle 8.0.

Deprecated java plugin conventions

The convention properties contributed by the java plugin have been deprecated and scheduled for removal in Gradle 8.0. They are replaced by the properties of JavaPluginExtension which can be configured in the java {} block.

Deprecated consumption of internal plugin configurations

Some of the core Gradle plugins declare configurations that are used by the plugin itself and are not meant to be published or consumed by another subproject directly. Gradle did not explicitly prohobit this. Gradle 7.1 deprecates consumption of those configurations and this will become an error in Gradle 8.0.

The following plugin configurations have been deprecated for consumption:

plugin configurations deprecated for consumption










jacocoAnt, jacocoAgent




providedCompile, providedRuntime

If your use case needs to consume any of the above mentioned configurations in another project, please create a separate consumable configuration that extends from the internal ones. For example:

plugins {
configurations {
    codenarc {
        // because currently this is consumable until Gradle 8.0 and can clash with the configuration below depending on the attributes set
        canBeConsumed = false
    codenarcConsumable {
        canBeConsumed = true
        canBeResolved = false
        // the attributes below make this configuration consumable by a `java-library` project using `implementation` configuration
        attributes {
            attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_RUNTIME))
            attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.LIBRARY))
            attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements, LibraryElements.JAR))
            attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling, Bundling.EXTERNAL))
            attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, objects.named(TargetJvmEnvironment, TargetJvmEnvironment.STANDARD_JVM));

Deprecated project-report plugin conventions

ProjectReportsPluginConvention is now deprecated and scheduled for removal in Gradle 8.0. Clients should configure the project report tasks directly. Also, tasks.withType(…​).configureEach(…​) can be used to configure each task of the same type (HtmlDependencyReportTask for example).

Deprecated war plugin conventions

WarPluginConvention is now deprecated and scheduled for removal in Gradle 8.0. Clients should configure the war task directly. Also, tasks.withType(War.class).configureEach(…​) can be used to configure each task of type War.

Deprecated ear plugin conventions

EarPluginConvention is now deprecated and scheduled for removal in Gradle 8.0. Clients should configure the ear task directly. Also, tasks.withType(Ear.class).configureEach(…​) can be used to configure each task of type Ear.

Deprecated custom source set interfaces

The following source set interfaces are now deprecated and scheduled for removal in Gradle 8.0:

Clients should configure the sources with their plugin-specific configuration:

For example, here’s how you configure the groovy sources from a plugin:

GroovySourceDirectorySet groovySources = sourceSet.getExtensions().getByType(GroovySourceDirectorySet.class);

Registering artifact transforms extending ArtifactTransform

When Gradle first introduced artifact transforms, it used the base class ArtifactTransform for implementing them. Gradle 5.3 introduced the interface TransformAction for implementing artifact transforms, replacing the previous class ArtifactTransform and addressing various shortcomings. Using the registration method DependencyHandler.registerTransform(Action) for ArtifactTransform has been deprecated. Migrate your artifact transform to use TransformAction and use DependencyHandler.registerTransform(Class, Action) instead. See the user manual for more information on implementing TransformAction.