What's new in Gradle 7.0

Gradle 7.0 banner

Gradle 7.0 is the next step in Gradle’s evolution in build automation and developer productivity. Here are the interesting changes from Gradle 6.0 to 7.0.

Gradle 7.0…

Upgrade now to try them with your build or start a new project with Gradle.

If you’re interested in staying up-to-date with new Gradle features and other developments, subscribe to our blog and follow us on Twitter.

We also post videos from past webinars for top Android build issues, dependency management techniques and release strategies.

Getting started with Gradle

Bootstrapping new projects with gradle init

The built-in init task can be used to quickly create a new Gradle build or convert a Maven build to a Gradle build.

Gradle generates projects with the latest recommended build authoring practices. Generated builds demonstrate the use of buildSrc for sharing common build logic and you can generate a multi-project build for JVM languages.

For projects being converted from Maven to Gradle, Gradle has support for generating Groovy DSL and Kotlin DSL scripts.

Downloadable Gradle samples

Gradle provides an index of samples to demonstrate different kinds of projects that can be built with Gradle.

The samples also show common problems that can be solved using the Groovy or Kotlin DSL, like adding integration tests to a Java project.

Performance improvements

Faster up-to-date checking with file system watching

Fast feedback for local incremental builds is crucial for developer productivity. This is especially true when your IDE uses Gradle to build and run tests for your project. File system watching speeds up local incremental builds by reducing the amount of disk I/O needed to determine what has changed since the previous build.

File system watching improvements

As of Gradle 7.0, this optimization is enabled by default on all supported operating systems including recent versions of Windows, Linux, and MacOS.

See the documentation for more details.

Faster Kotlin DSL script compilation

Gradle compiles Kotlin DSL build scripts (*.gradle.kts) faster with less memory pressure.

When changing shared build logic such as code in the buildSrc directory, Gradle can also completely skip compilation of unaffected build script files.

Most builds can expect a noticeably shorter feedback loop when editing Kotlin DSL build logic with Gradle 7.0.

Kotlin script compilation

Faster builds by skipping more work when using build cache

Gradle contains several changes to increase the hit rate from the build cache by selectively ignoring various changes that do not affect the behaviour of the system such as empty directories, comments or whitespace in property files and others.

Faster builds with the experimental configuration cache

Before running any task, Gradle needs to run the configuration phase. Currently, this is done on every build invocation and can cause a noticeable delay, especially in large projects.

Configuration cache improves build performance by caching the result of the configuration phase. Using the configuration cache, Gradle can skip the configuration phase entirely when nothing that affects the build configuration has changed, making subsequent builds much faster.

In addition, more work is executed in parallel when using the configuration cache, accelerating the execution phase of the build too.

Note that this feature is currently experimental, not enabled by default, and not supported by all core plugins as of Gradle 7.0.

configuration caching demo

Learn more about this new feature and its impact in the configuration cache documentation.

Faster PMD execution via incremental analysis

The PMD plugin uses incremental analysis by default. This can significantly reduce analysis time on subsequent builds.

For builds relying on a version of PMD older than 6.0.0, you will need to explicitly disable incremental analysis.

Faster ephemeral builds

Ephemeral build machines pay a high cost when they re-download all dependencies used by the build. Gradle 7.0 has the following features to limit the impact to these kinds of builds by reusing the dependency cache across machines.

Relocating dependency cache

The Gradle dependency cache under $GRADLE_HOME/caches/modules-2 can be relocated to another directory or host for dependencies cached. When moved to a new location or seeded into a host image, builds using the dependency cache will not need to access the network to download artifacts or metadata if the dependencies have already been downloaded.

Note that creating the cache and consuming it should be done using a compatible Gradle version.

See the documentation for more details.

Sharing a read-only dependency cache

Gradle offers the ability to share a dependency cache between multiple Gradle instances.

This makes it possible to have a single shared directory that contains the dependencies required by all builds.

  • Each container will have access to the shared read-only dependency cache, which avoids redundant downloads between builds.
  • This cache can be safely shared between containers without creating separate copies of it.

Refer to the user manual to learn how to set up the shared dependency cache.

Usability and new features

Toolchain support for JVM projects

By default, Gradle uses the same Java version for running Gradle itself and building JVM projects, but this is not always desirable.

Building projects with different Java versions on different developer machines and CI servers may lead to unexpected issues. Additionally, you may want to build a project using a Java version that running Gradle is not compatible with.

Gradle provides a way to set up a toolchain to use to build and test your project through the java extension:

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(14)
    }
}

Gradle will detect local Java installations and other common installation locations from popular package managers like asdf-vm, jabba and SDKMAN!. If no matching Java version is available locally that matches the requirements of the build, Gradle will download a matching JDK from AdoptOpenJDK’s website.

Java toolchains demo

See the toolchain documentation in the user manual.

Building, testing and running Java Modules

Gradle supports the Java Module System with everything you need to compile and execute tests for Java modules.

See the included samples.

Conventions for handling user-provided credentials

Builds sometimes require users to supply credentials. For example, credentials might be required to authenticate with an artifact repository in order to publish an artifact. It’s a good practice to keep credentials outside the build script.

Gradle has an API that makes working with credentials easier by establishing a convention to supply credentials using Gradle properties that can be provided to the build as command-line arguments, environment variables, or as values in a gradle.properties file. It also introduces fail-fast behavior when Gradle knows that the build will need credentials at some point and the credentials are missing.

For more details on using the new API to authenticate with artifact repositories, see the user manual section as well as an updated sample.

Tasks can be executed for included builds from the command-line

Gradle allows users to execute tasks from included builds directly from the command line. For example, if your build includes my-other-project as an included build and it has a subproject sub with a task foo, then you can execute foo with the following command:

gradle :my-other-project:sub:foo

Note, unlike a multi-project build, running gradle build will not run the build task in all of the included builds. You could introduce task dependencies to lifecycle tasks in included builds if you wanted to recreate this behavior for included builds.

Single dependency lock file format

Dependency locking is a mechanism for ensuring reproducible builds when using dynamic dependency versions.

Gradle 7.0 uses a single lock file to lock dynamic dependencies to their resolved versions.

Previous versions of Gradle used one file per configuration. Gradle will automatically migrate to the single lock file.

Security improvements

Dependency verification

Typical projects use a large number of external dependencies which put them at risk of using untrusted code. For example, someone may accidentally introduce a malicious code via a transitive dependency. Similarly, your build script itself may be vulnerable to malicious code execution via a compromised plugin.

In an effort to mitigate these risks, Gradle provides dependency verification. Dependency verification makes it possible to verify both the checksums and the signatures of dependencies and plugins used during a build.

By enabling dependency verification, Gradle will:

  • make sure that the dependencies haven’t been tampered with (by verifying their checksums)
  • ensure the provenance of dependencies and plugins you use (by verifying their signatures)

and therefore reduce the risks of shipping malicious code to production.

Refer to the user manual for a complete explanation about how to set up dependency verification.

Declaring exclusive repository content

Gradle lets you declare which repositories should be searched for specific dependencies.

Gradle also lets you declare exclusive content that can only be found in one repository and it shouldn’t be searched for in any other.

Refer to the user manual for details.

Verifying the integrity of Gradle Wrappers

The Gradle Wrapper is a binary blob of executable code that is checked into millions of GitHub repositories. There are security implications when accepting changes to gradle-wrapper.jar that may not be apparent.

We have created an official GitHub Action that allows projects on GitHub to automatically verify that the gradle-wrapper.jar in their repository was released by Gradle.

Gradle wrapper verification

You can still manually verify the gradle-wrapper.jar by following the instructions in the user manual.

Dependency management

Consistent dependency resolution

Dependency resolution between configurations happens in isolation. This can cause a problem where the runtime classpath of tests could use different versions than the runtime classpath of production code.

To mitigate this problem, Gradle lets you declare consistency between dependency configurations so that the version of common dependencies between one classpath and the other are aligned.

Central declaration of repositories

Conveniently define repositories for the whole build in settings.gradle (.kts):

dependencyResolutionManagement {
    repositories {
        mavenCentral ()
    }
}

This allows Gradle to ensure that you use the same repositories for resolving dependencies in all projects of the build. Learn more by reading how to declare repositories for the whole build.

Central declaration of component metadata rules

Declare component metadata rules in a central place in settings.gradle (.kts):

dependencyResolutionManagement {
    components {
        withModule ('com.google.guava: guava', GuavaRule)
    }
}

You can learn more about declaring rules globally in the user manual.

Experimental version catalogs for central declaration of dependency versions

There are a number of ways to share dependency versions between projects in multi-project builds. For example, users can declare versions or dependency coordinates directly in build scripts (in the ext block), external files (e.g dependencies.gradle), in buildSrc or even dedicated plugins. There wasn’t, however, any standard mechanism to do this which would combine the advantages of each approach.

Gradle introduced experimental version catalogs to enable build authors to centralize the dependency coordinates (group, artifact, version) of their third party dependencies in a conventional configuration file and declare the actual dependencies in a type-safe way.

Experimental type-safe project accessors

Gradle has an experimental feature for type-safe project accessors which enables code completion in IDEs for declaring dependencies on other projects.

Build authoring

Using included builds for local plugin development

Developing plugins as part of a composite build, to organize build logic in convention plugins, was so far only possible for project plugins (plugins applied in build.gradle(.kts) files). Settings plugins (plugins applied in settings.gradle(.kts) files) always had to be developed in isolation and published to a binary repository.

Gradle provides a DSL construct in the settings file for including plugin builds.

Builds included like that can provide both project and settings plugins.

pluginManagement {
    includeBuild("../my-settings-plugin")
}
plugins {
    id("my.settings-plugin") 
}

The above example assumes that the included build defines a settings plugin with the id my.settings-plugin.

Precompiled Groovy DSL script plugins

Script plugins are a convenient way to split up and organize a long build script, but they have some limitations and quirks.

Precompiled script plugins look like regular build scripts but have all of the advantages of binary plugins. They can:

  • be published to a private repository or the Plugin Portal,
  • be tested using TestKit,
  • be applied using the plugins {} block,
  • use the plugins {} block to apply other plugins.

Precompiled script plugins can be written using the Groovy DSL and Kotlin DSL.

Precompiled script plugins are covered in more depth in the user manual. There is also a sample that demonstrates the feature in action.

Included builds are visible to buildSrc

We recommend that builds use the specially named buildSrc build to organize imperative and common build logic.

Sometimes, you may also need to share build logic between buildSrc itself and your root build. In the previous releases, that was not possible because buildSrc could not access build logic from other included builds.

Gradle makes it possible to share build logic between buildSrc and the root build or any other included build. This makes it easier to share common repository declarations or conventions between buildSrc and other builds as demonstrated in this sample.

Other changes you might have missed

Kotlin 1.4

Kotlin build scripts written in Gradle 7.0 default to the Kotlin 1.4 compatibility level.

Groovy 3.0

In order to support JDK 16 and keep up to date with the latest Groovy release, Gradle has been upgraded to use Groovy 3 in Groovy DSL build scripts. Groovy 3 comes with a new parser and host of other new features and capabilities that make interoperability with new Java features easier.

There are some incompatibilities between Groovy 2 and 3, that may cause issues when upgrading to Gradle 7.0.

You may be affected by the Groovy upgrade if:

  • You are using the Groovy DSL for your build scripts (.gradle files)
  • You are using a Gradle plugin implemented in Groovy
  • You are building a Gradle plugin implemented in Groovy

You should not be impacted by the upgrade if:

  • You are only using the Kotlin DSL (.gradle.kts files)
  • You are using Groovy for your production code only (you can choose which version of Groovy you need)

Refer to the Gradle upgrade guide to learn more about upgrading your build and plugins to be compatible with Groovy 3.

In order to learn more about the improvements and new features in Groovy 3.0, refer to the Groovy project’s release notes.


How to upgrade

We’ve provided a document to help you upgrade from Gradle 6.x to Gradle 7.0. If you’re using something older than Gradle 6.0, you may want to see all the new things in Gradle 6.0 first.

Before upgrading, we recommend you:

  • Upgrade to Gradle 6.9 using the Gradle wrapper. gradle wrapper --gradle-version=6.9
  • Run gradle help --scan to list all uses of deprecated Gradle APIs with their locations.
  • Update your Gradle plugins, especially those listed in the deprecations report from the Build Scan™.
  • See the troubleshooting guide or reach out on the community forums if you get stuck.

You can share feedback with the Gradle team via @gradle on Twitter. Go forth and Build Happiness!