:gradle-issues: https://github.com/gradle/gradle/issues/

[[config_cache]]
= Configuration cache

// Run tests for snippets included in this chapter with:
// ./gradlew :docs:docsTest --tests="ExemplarExternalSamplesFunctionalTest.snippet-configuration-cache-*"
// ./gradlew :docs:docsTest --tests="ExemplarExternalSamplesFunctionalTest.snippet-value-providers-*"

[NOTE]
====
The configuration cache is an <<feature_lifecycle.adoc#feature_lifecycle,incubating>> feature, and the details described here may change.
====

[[config_cache:intro]]
== Introduction

The configuration cache is a feature that significantly improves build performance by caching the result of the <<build_lifecycle#build_lifecycle,configuration phase>> and reusing this for subsequent builds.
Using the configuration cache, Gradle can skip the configuration phase entirely when nothing that affects the build configuration, such as build scripts, has changed.
Gradle also applies some performance improvements to task execution as well.

The configuration cache is conceptually similar to the <<build_cache#build_cache,build cache>>, but caches different information.
The build cache takes care of caching the outputs and intermediate files of the build, such as task outputs or artifact transform outputs.
The configuration cache takes care of caching the build configuration for a particular set of tasks.
In other words, the configuration cache caches the output of the configuration phase, and the build cache caches the outputs of the execution phase.

[IMPORTANT]
====
This feature is currently *_highly experimental_* and not enabled by default.

Not all <<configuration_cache#config_cache:plugins:core, core Gradle plugins>> are supported.
Your build and the plugins you depend on might require changes to fulfil the <<configuration_cache#config_cache:requirements, requirements>>.
Some Gradle features are <<configuration_cache#config_cache:not_yet_implemented, not yet implemented>>.
Importing and syncing Gradle builds in IDEs is not improved by configuration caching yet.
====

[[config_cache:intro:how_does_it_work]]
=== How does it work?

When the configuration cache is enabled and you run Gradle for a particular set of tasks, for example by running `gradlew check`, Gradle checks whether a configuration cache entry is available for the requested set of tasks.
If available, Gradle uses this entry instead of running the configuration phase.
The cache entry contains information about the set of tasks to run, along with their configuration and dependency information.

The first time you run a particular set of tasks, there will be no entry in the configuration cache for these tasks and so Gradle will run the configuration phase as normal:

1. Run init scripts.
2. Run the settings script for the build, applying any requested settings plugins.
3. Configure and build the `buildSrc` project, if present.
4. Run the builds scripts for the build, applying any requested project plugins.
5. Calculate the task graph for the requested tasks, running any deferred configuration actions.

Following the configuration phase, Gradle writes the state of the task graph to the configuration cache, taking a snapshot for later Gradle invocations.
The execution phase then runs as normal.
This means you will not see any build performance improvement the first time you run a particular set of tasks.

When you subsequently run Gradle with this same set of tasks, for example by running `gradlew check` again, Gradle will load the tasks and their configuration directly from the configuration cache and skip the configuration phase entirely.
Before using a configuration cache entry, Gradle checks that none of the "build configuration inputs", such as build scripts, for the entry have changed.
If a build configuration input has changed, Gradle will not use the entry and will run the configuration phase again as above, saving the result for later reuse.

Build configuration inputs include:

- Init scripts, settings scripts, build scripts.
- System properties, Gradle properties and configuration files used during the configuration phase, accessed using value suppliers such as providers for properties, environment variables etc...
- `buildSrc` build configuration inputs and source files.

[[config_cache:intro:performance_improvements]]
=== Performance improvements

Apart from skipping the configuration phase, the configuration cache provides some additional performance improvements:

- All tasks run in parallel by default.
- Dependency resolution is cached.

[[config_cache:in_action]]
=== Configuration caching in action

image::configuration-cache/running-help.gif[]

[[config_cache:usage]]
== Using the configuration cache

It is recommended to get started with the simplest task invocation possible.
Running `help` with the configuration cache enabled is a good first step:

----
❯ gradle --configuration-cache help
include::{snippetsPath}/configurationCache/noProblem/tests/store.out[]
...
BUILD SUCCESSFUL in 4s
1 actionable task: 1 executed
Configuration cache entry stored.
----

Running this for the first time, the configuration phase is executed, calculating the task graph.

Then, run the same command again.
This will reuse the cached configuration:

----
❯ gradle --configuration-cache help
include::{snippetsPath}/configurationCache/noProblem/tests/load.out[]
...
BUILD SUCCESSFUL in 500ms
1 actionable task: 1 executed
Configuration cache entry reused.
----

If it succeeds on your build, congratulations, you can now try with more useful tasks.
You should target your development loop.
A good example is running tests after making incremental changes.

If any problem is found caching or reusing the configuration, an HTML report is generated to help you diagnose and fix the issues.
See the <<configuration_cache#config_cache:troubleshooting>> section below for more information.

Keep reading to learn how to tweak the configuration cache, manually invalidate the state if something goes wrong and use the configuration cache from an IDE.

[[config_cache:usage:enable]]
=== Enabling the configuration cache

By default, the configuration cache is not enabled.
It can be enabled from the command line:

----
❯ gradle --configuration-cache
----

It can also be enabled persistently in a `gradle.properties` file:

[source,properties]
----
org.gradle.unsafe.configuration-cache=true
----

If it is enabled in a `gradle.properties` file, it can be disabled on the command line for one build invocation:

----
❯ gradle --no-configuration-cache
----

[[config_cache:usage:ignore_problems]]
=== Ignoring problems

By default, Gradle will fail the build if any configuration cache problems are encountered.
When gradually improving your plugin or build logic to support the configuration cache it can be useful to temporarily turn problems into warnings.

This can be done from the command line:

----
❯ gradle --configuration-cache-problems=warn
----

or in a `gradle.properties` file:

[source,properties]
----
org.gradle.unsafe.configuration-cache-problems=warn
----

[[config_cache:usage:max_problems]]
=== Allowing a maximum number of problems

When configuration cache problems are turned into warnings, Gradle will fail the build if `512` problems are found by default.

This can be adjusted by specifying an allowed maximum number of problems on the command line:

----
❯ gradle -Dorg.gradle.unsafe.configuration-cache.max-problems=5
----

or in a `gradle.properties` file:

[source,properties]
----
org.gradle.unsafe.configuration-cache.max-problems=5
----

[[config_cache:usage:invalidate]]
=== Invalidating the cache

The configuration cache is automatically invalidated when inputs to the configuration phase change.
However, certain inputs are not tracked yet, so you may have to manually invalidate the configuration cache when untracked inputs to the configuration phase change.
This can happen if you <<configuration_cache#config_cache:usage:ignore_problems,ignored problems>>.
See the <<configuration_cache#config_cache:requirements>> and <<configuration_cache#config_cache:not_yet_implemented>> sections below for more information.

The configuration cache state is stored on disk in a directory named `.gradle/configuration-cache` in the root directory of the Gradle build in use.
If you need to invalidate the cache, simply delete that directory:

----
❯ rm -rf .gradle/configuration-cache
----

Configuration cache entries are checked periodically (at most every 24 hours) for whether they are still in use.
They are deleted if they haven't been used for 7 days.

[[config_cache:ide]]
== IDE support

If you enable and configure the configuration cache from your `gradle.properties` file, then the configuration cache will be enabled when your IDE delegates to Gradle.
There's nothing more to do.

`gradle.properties` is usually checked in source control.
If you don't want to enable the configuration cache for your whole team yet you can also enable the configuration cache from your IDE only as explained below.

Note that syncing a build from an IDE doesn't benefit from the configuration cache, only running tasks does.

[[config_cache:ide:intellij]]
=== IntelliJ based IDEs

In IntelliJ IDEA or Android Studio this can be done in two ways, either globally or per run configuration.

To enable it for the whole build, go to `Run > Edit configurations...`.
This will open the IntelliJ IDEA or Android Studio dialog to configure Run/Debug configurations.
Select `Templates > Gradle` and add the necessary system properties to the `VM options` field.

For example to enable the configuration cache, turning problems into warnings, add the following:

----
-Dorg.gradle.unsafe.configuration-cache=true -Dorg.gradle.unsafe.configuration-cache-problems=warn
----

You can also choose to only enable it for a given run configuration.
In this case, leave the `Templates > Gradle` configuration untouched and edit each run configuration as you see fit.

Combining these two ways you can enable globally and disable for certain run configurations, or the opposite.

[TIP]
====
You can use the link:https://github.com/JetBrains/gradle-idea-ext-plugin[gradle-idea-ext-plugin] to configure IntelliJ run configurations from your build.
This is a good way to enable the configuration cache only for the IDE.
====

[[config_cache:ide:eclipse]]
=== Eclipse IDEs

In Eclipse IDEs you can enable and configure the configuration cache through Buildship in two ways, either globally or per run configuration.

To enable it globally, go to `Preferences > Gradle`.
You can use the properties described above as system properties.
For example to enable the configuration cache, turning problems into warnings, add the following JVM arguments:

* `-Dorg.gradle.unsafe.configuration-cache=true`
* `-Dorg.gradle.unsafe.configuration-cache-problems=warn`

To enable it for a given run configuration, go to `Run configurations...`, find the one you want to change, go to `Project Settings`, tick the `Override project settings` checkbox and add the same system properties as a `JVM argument`.

Combining these two ways you can enable globally and disable for certain run configurations, or the opposite.

[[config_cache:plugins]]
== Supported plugins

The configuration cache is brand new and introduces new requirements for plugin implementations.
As a result, both core Gradle plugins, and community plugins need to be adjusted.
This section provides information about the current support in <<configuration_cache#config_cache:plugins:core, core Gradle plugins>> and <<configuration_cache#config_cache:plugins:community, community plugins>>.

[[config_cache:plugins:core]]
=== Core Gradle plugins

Not all <<plugin_reference#plugin_reference, core Gradle plugins>> support configuration caching yet.

[cols=3*]
|===
h| JVM languages and frameworks
h| Native languages
h| Packaging and distribution

a|
[horizontal]
link:{gradle-issues}13455[[.green]#✓#]:: <<java_plugin.adoc#java_plugin,Java>>
link:{gradle-issues}13455[[.green]#✓#]:: <<java_library_plugin.adoc#java_library_plugin,Java Library>>
link:{gradle-issues}13455[[.green]#✓#]:: <<java_platform_plugin.adoc#java_platform_plugin,Java Platform>>
link:{gradle-issues}13460[[.yellow]#⚠#]:: <<groovy_plugin.adoc#groovy_plugin,Groovy>>
link:{gradle-issues}13461[[.red]#✖#]:: <<scala_plugin.adoc#scala_plugin,Scala>>
link:{gradle-issues}13462[[.yellow]#⚠#]:: <<antlr_plugin.adoc#antlr_plugin,ANTLR>>

a|
[horizontal]
link:{gradle-issues}13484[[.red]#✖#]:: <<cpp_application_plugin.adoc#cpp_application_plugin,C++ Application>>
link:{gradle-issues}13485[[.red]#✖#]:: <<cpp_library_plugin.adoc#cpp_library_plugin,C++ Library>>
link:{gradle-issues}13514[[.red]#✖#]:: <<cpp_unit_test_plugin.adoc#cpp_unit_test_plugin,C++ Unit Test>>
link:{gradle-issues}13515[[.red]#✖#]:: <<swift_application_plugin.adoc#swift_application_plugin,Swift Application>>
link:{gradle-issues}13487[[.red]#✖#]:: <<swift_library_plugin.adoc#swift_library_plugin,Swift Library>>
link:{gradle-issues}13488[[.red]#✖#]:: <<xctest_plugin.adoc#xctest_plugin,XCTest>>

a|
[horizontal]
link:{gradle-issues}13455[[.green]#✓#]:: <<application_plugin.adoc#application_plugin,Application>>
link:{gradle-issues}13455[[.green]#✓#]:: <<war_plugin.adoc#war_plugin,WAR>>
link:{gradle-issues}13455[[.green]#✓#]:: <<ear_plugin.adoc#ear_plugin,EAR>>
link:{gradle-issues}13468[[.yellow]#⚠#]:: <<publishing_maven.adoc#publishing_maven,Maven Publish>>
link:{gradle-issues}13469[[.red]#✖#]:: <<publishing_ivy.adoc#publishing_ivy,Ivy Publish>>
[.gray]#🚫#:: <<maven_plugin.adoc#maven_plugin,Legacy Maven Plugin>>
link:{gradle-issues}13455[[.green]#✓#]:: <<distribution_plugin.adoc#distribution_plugin,Distribution>>
link:{gradle-issues}13455[[.green]#✓#]:: <<java_library_distribution_plugin.adoc#java_library_distribution_plugin,Java Library Distribution>>

h| Code analysis
h| IDE integration
h| Utility

a|
[horizontal]
link:{gradle-issues}13475[[.red]#✖#]:: <<checkstyle_plugin.adoc#checkstyle_plugin,Checkstyle>>
link:{gradle-issues}13476[[.red]#✖#]:: <<pmd_plugin.adoc#pmd_plugin,PMD>>
link:{gradle-issues}13477[[.red]#✖#]:: <<jacoco_plugin.adoc#jacoco_plugin,JaCoCo>>
link:{gradle-issues}13478[[.red]#✖#]:: <<codenarc_plugin.adoc#codenarc_plugin,CodeNarc>>

a|
[horizontal]
link:{gradle-issues}13479[[.red]#✖#]:: <<eclipse_plugin.adoc#eclipse_plugin,Eclipse>>
link:{gradle-issues}13480[[.red]#✖#]:: <<idea_plugin.adoc#idea_plugin,IntelliJ IDEA>>
link:{gradle-issues}13482[[.red]#✖#]:: <<visual_studio_plugin.adoc#visual_studio_plugin,Visual Studio>>
link:{gradle-issues}13483[[.red]#✖#]:: <<xcode_plugin.adoc#xcode_plugin,Xcode>>

a|
[horizontal]
link:{gradle-issues}13455[[.green]#✓#]:: <<base_plugin.adoc#base_plugin,Base>>
link:{gradle-issues}13466[[.yellow]#⚠#]:: <<build_init_plugin.adoc#build_init_plugin,Build Init>>
link:{gradle-issues}13470[[.red]#✖#]:: <<signing_plugin.adoc#signing_plugin,Signing>>
link:{gradle-issues}13455[[.green]#✓#]:: <<java_gradle_plugin.adoc#java_gradle_plugin,Java Plugin Development>>
link:{gradle-issues}13472[[.red]#✖#]:: <<custom_plugins.adoc#sec:precompiled_plugins,Groovy DSL Plugin Development>>
link:{gradle-issues}13472[[.red]#✖#]:: <<kotlin_dsl.adoc#sec:kotlin-dsl_plugin,Kotlin DSL Plugin Development>>
link:{gradle-issues}13473[[.red]#✖#]:: <<project_report_plugin.adoc#project_report_plugin,Project Report Plugin>>

|===

[horizontal]
[.green]#✓#:: Supported plugin
[.yellow]#⚠#:: Partially supported plugin
[.red]#✖#:: Unsupported plugin
[.gray]#🚫#:: Won't fix

[[config_cache:plugins:community]]
=== Community plugins

Please refer to issue link:{gradle-issues}13490[gradle/gradle#13490] to learn about the status of community plugins.

[[config_cache:troubleshooting]]
== Troubleshooting

The following sections will go through some general guidelines on dealing with problems with the configuration cache.
This applies to both your build logic and to your Gradle plugins.

Upon failure to serialize the state required to run the tasks, an HTML report of detected problems is generated.
The Gradle failure output includes a clickable link to the report.
This report is useful and allows you to drill down into problems, understand what is causing them.

Let's look at a simple example build script that contains a couple problems:

====
include::sample[dir="snippets/configurationCache/problemsGroovy/groovy",files="build.gradle[]"]
include::sample[dir="snippets/configurationCache/problemsKotlin/kotlin",files="build.gradle.kts[]"]
====
<1> <<configuration_cache#config_cache:requirements:undeclared_sys_prop_read, Undeclared system property read at configuration time>>
<2> <<configuration_cache#config_cache:requirements:use_project_during_execution, Using the `Project` object at execution time>>

Running that task fails and print the following in the console:

----
❯ gradle --configuration-cache someTask -DsomeMessage=hello
...
include::{snippetsPath}/configurationCache/problemsGroovy/tests/store.out[]
Configuration cache entry stored.
----

Details can be found in the linked HTML report:

image::configuration-cache/problems-report.png[]

The report displays the set of problems twice.
First grouped by problem message, then grouped by task.
The former allows you to quickly see what classes of problems your build is facing.
The latter allows you to quickly see which tasks are problematic.
In both cases you can expand the tree in order to discover where the culprit is in the object graph.

[TIP]
====
Problems displayed in the report have links to the corresponding <<configuration_cache#config_cache:requirements,requirement>> where you can find guidance on how to fix the problem or to the corresponding <<configuration_cache#config_cache:not_yet_implemented,not yet implemented>> feature.

When changing your build or plugin to fix the problems you should consider <<configuration_cache#config_cache:testing, testing your build logic with TestKit>>.
====

At this stage, you can decide to either <<configuration_cache#config_cache:usage:ignore_problems, turn the problems into warnings>> and continue exploring how your build reacts to the configuration cache, or fix the problems at hand.

Let's ignore the problems reported when storing the configuration cache, and run the same build again to see what happens when reusing the problematic cached configuration:

----
❯ gradle --configuration-cache someTask -DsomeDestination=dest
...
include::{snippetsPath}/configurationCache/problemsGroovy/tests/load.out[]
Configuration cache entry reused.
----

The build fails again, reporting the observed problems.
The first problem that happened at configuration time when storing is not reported given the configuration phase was skipped.
The second problem about using `Project` at execution time is reported.

With the help of the links present in the console problem summary and in the HTML report we can fix our problems.
Here's a fixed version of the build script:

====
include::sample[dir="snippets/configurationCache/problemsFixed/groovy",files="build.gradle[tags=fixed]"]
include::sample[dir="snippets/configurationCache/problemsFixed/kotlin",files="build.gradle.kts[tags=fixed]"]
====
<1> we turned our ad-hoc task into a proper task class
<2> this allows the injection of the `FileSystemOperations` service, a supported replacement for `project.copy {}`
<3> finally, we declare the system property as a build configuration input, used at configuration time and wire it to our task input

Running the task twice now succeeds without reporting any problem and reusing the configuration cache on the second run:

----
❯ gradle --configuration-cache someTask -DsomeDestination=dest
include::{snippetsPath}/configurationCache/problemsFixed/tests/store.out[]
Configuration cache entry stored.
❯ gradle --configuration-cache someTask -DsomeDestination=dest
include::{snippetsPath}/configurationCache/problemsFixed/tests/load.out[]
Configuration cache entry reused.
----

But, what if we change the value of the system property?

----
❯ gradle --configuration-cache someTask -DsomeDestination=another
include::{snippetsPath}/configurationCache/problemsFixed/tests/store-another.out[]
Configuration cache entry stored.
----

The previous configuration cache entry could not be reused, and the task graph had to be calculated again.
This is because we read the system property at configuration time, hence requiring Gradle to run the configuration phase again when the value of that property changes.
Fixing that is as simple as wiring the system property directly, without reading it at configuration time.

====
include::sample[dir="snippets/configurationCache/problemsFixedReuse/groovy",files="build.gradle[tags=fixed-reuse]"]
include::sample[dir="snippets/configurationCache/problemsFixedReuse/kotlin",files="build.gradle.kts[tags=fixed-reuse]"]
====
<1> wire the declared system property directly, without reading it at configuration time

With those changes in place we can run the task twice, changing the system property value:

----
❯ gradle --configuration-cache someTask -DsomeDestination=dest
include::{snippetsPath}/configurationCache/problemsFixedReuse/tests/store.out[]
Configuration cache entry stored.
❯ gradle --configuration-cache someTask -DsomeDestination=another
include::{snippetsPath}/configurationCache/problemsFixedReuse/tests/load-another.out[]
Configuration cache entry reused.
----

We're now done with fixing the problems with this simple task.

Keep reading to learn how to adopt the configuration cache for your build or your plugins.

[[config_cache:adoption]]
== Adoption steps

An important prerequisite is to keep your Gradle and plugins versions up to date.
The following explores the recommended steps for a successful adoption.
It applies both to builds and plugins.
While going through these steps, keep in mind the HTML report and the solutions explained in the <<configuration_cache#config_cache:requirements, requirements>> chapter below.

Start with `:help`::
Always start by trying your build or plugin with the simplest task `:help`.
This will exercise the minimal configuration phase of your build or plugin.

Progressively target useful tasks::
Don't go with running `build` right away.
You can also use `--dry-run` to discover more configuration time problems first.
+
When working on a build, progressively target your development feedback loop.
For example, running tests after making some changes to the source code.
+
When working on a plugin, progressively target the contributed or configured tasks.

Explore by turning problems into warnings::
Don't stop at the first build failure and <<configuration_cache#config_cache:usage:ignore_problems, turn problems into warnings>> to discover how your build and plugins behave.
If a build fails, use the HTML report to reason about the reported problems related to the failure.
Continue running more useful tasks.
+
This will give you a good overview of the nature of the problems your build and plugins are facing.
Remember that when turning problems into warnings you might need to <<configuration_cache#config_cache:usage:invalidate, manually invalidating the cache>> in case of troubles.

Step back and fix problems iteratively::
When you feel you know enough about what needs to be fixed, take a step back and start iteratively fixing the most important problems.
Use the HTML report and this documentation to help you in this journey.
+
Start with problems reported when _storing_ the configuration cache.
Once fixed, you can rely on a valid cached configuration phase and move on to fixing problems reported when _loading_ the configuration cache if any.

Report encountered issues::
If you face a problem with a <<configuration_cache#config_cache:not_yet_implemented, Gradle feature>> or with a <<configuration_cache#config_cache:plugins:core, Gradle core plugin>> that is not covered by this documentation, please report an issue on link:https://github.com/gradle/gradle/issues/new/choose[`gradle/gradle`].
+
If you face a problem with a community Gradle plugin, see if it is already listed at link:{gradle-issues}13490[gradle/gradle#13490] and consider reporting the issue to the plugin's issue tracker.
+
A good way to report such issues is by providing information such as:
+
* a link to this very documentation,
* the plugin version you tried,
* the custom configuration of the plugin if any, or ideally a reproducer build,
* a description of what fails, for example problems with a given task
* a copy of the build failure,
* the self-contained `configuration-cache-report.html` file.

Test, test, test::
Consider adding tests for your build logic.
See the below section on <<configuration_cache#config_cache:testing, testing your build logic>> for the configuration cache.
This will help you while iterating on the required changes and prevent future regressions.

Roll it out to your team::
Once you have your developer workflow working, for example running tests from the IDE, you can consider enabling it for your team.
A faster turnaround when changing code and running tests could be worth it.
You'll probably want to do this as an opt-in first.
+
If needed, turn problems into warnings and set the maximum number of allowed problems in your build `gradle.properties` file.
Keep the configuration cache disabled by default.
Let your team know they can opt-in by, for example, enabling the configuration cache on their IDE run configurations for the supported workflow.
+
Later on, when more workflows are working, you can flip this around.
Enable the configuration cache by default, configure CI to disable it, and if required communicate the unsupported workflow(s) for which the configuration cache needs to be disabled.

[[config_cache:testing]]
== Testing your build logic

The Gradle TestKit (a.k.a. just TestKit) is a library that aids in testing Gradle plugins and build logic generally.
For general guidance on how to use TestKit, see the <<test_kit.adoc#test_kit,dedicated chapter>>.

To enable configuration caching in your tests, you can pass the `--configuration-cache` argument to link:{javadocPath}/org/gradle/testkit/runner/GradleRunner.html[GradleRunner] or use one of the other methods described in <<configuration_cache.adoc#config_cache:usage:enable,Enabling the configuration cache>>.

You need to run your tasks twice.
Once to prime the configuration cache.
Once to reuse the configuration cache.

.Testing the configuration cache
====
include::sample[dir="snippets/configurationCache/testKit/groovy",files="src/test/groovy/org/example/BuildLogicFunctionalTest.groovy[tags=functional-test-configuration-cache]"]
include::sample[dir="snippets/configurationCache/testKit/kotlin",files="src/test/kotlin/org/example/BuildLogicFunctionalTest.kt[tags=functional-test-configuration-cache]"]
====
<1> First run primes the configuration cache.
<2> Second run reuses the configuration cache.
<3> Assert that the configuration cache gets reused.

If problems with the configuration cache are found then Gradle will fail the build reporting the problems, and the test will fail.

[[config_cache:requirements]]
== Requirements

In order to capture the state of the task graph to the configuration cache and reload it again in a later build, Gradle applies certain requirements to tasks and other build logic.
Each of these requirements is treated as a configuration cache "problem" and fails the build if violations are present.

For the most part these requirements are actually surfacing some undeclared inputs.
In other words, using the configuration cache is an opt-in to more strictness, correctness and reliability for all builds.

The following sections describe each of the requirements and how to change your build to fix the problems.

[[config_cache:requirements:disallowed_types]]
=== Certain types must not be referenced by tasks

There are a number of types that task instances must not reference from their fields.
The same applies to task actions as closures such as `doFirst {}` or `doLast {}`.

These types fall into some categories as follows:

* Live JVM state types
* Gradle model types
* Dependency management types

In all cases the reason these types are disallowed is that their state cannot easily be stored or recreated by the configuration cache.

Live JVM state types (e.g. `ClassLoader`, `Thread`, `OutputStream`, `Socket` etc...) are simply disallowed.
These types almost never represent a task input or output.

Gradle model types (e.g. `Gradle`, `Settings`, `Project`, `SourceSet`, `Configuration` etc...) are usually used to carry some task input that should be explicitly and precisely declared instead.

For example, if you reference a `Project` in order to get the `project.version` at execution time, you should instead directly declare the _project version_  as an input to your task using a `Property<String>`.
Another example would be to reference a `SourceSet` to later get the source files, the compilation classpath or the outputs of the source set.
You should instead declare these as a `FileCollection` input and reference just that.

The same requirement applies to dependency management types with some nuances.

Some types, such as `Configuration`, don't make good task input parameters, as they hold a lot of irrelevant state, and it is better to model these inputs as something more precise. We don't intend to make these types serializable at all.
For example, if you reference a `Configuration` to later get the resolved files, you should instead declare a `FileCollection` as an input to your task.

Referencing dependency resolution results is also disallowed (e.g. `ArtifactResolutionQuery`, `ResolvedArtifact`, `ArtifactResult` etc...).
For example, if you reference some `ResolvedArtifactResult` instances, you should instead declare some `ArtifactCollection` as an input to your task.
The rule of thumb is that tasks must not reference _resolved_ results, but lazy specifications instead, in order to do the dependency resolution at execution time.
Some APIs are missing and cannot yet be used as task inputs, for example it is currently not possible for task actions to reason about the dependency _graph_, see link:{gradle-issues}12871[gradle/gradle#12871].

Some types, such as `Publication` or `Dependency` are not serializable, but could be. We may, if necessary, allow these to be used as task inputs directly.

Here's an example of a problematic task type referencing a `SourceSet`:

====
include::sample[dir="snippets/configurationCache/disallowedTypes/groovy",files="build.gradle[tags=task-type]"]
include::sample[dir="snippets/configurationCache/disallowedTypes/kotlin",files="build.gradle.kts[tags=task-type]"]
====
<1> this will be reported as a problem because referencing `SourceSet` is not allowed

The following is how it should be done instead:

====
include::sample[dir="snippets/configurationCache/disallowedTypesFixed/groovy",files="build.gradle[tags=task-type]"]
include::sample[dir="snippets/configurationCache/disallowedTypesFixed/kotlin",files="build.gradle.kts[tags=task-type]"]
====
<1> no more problems reported, we now reference the supported type `FileCollection`

In the same vein, if you encounter the same problem with an ad-hoc task declared in a script as follows:

====
include::sample[dir="snippets/configurationCache/disallowedTypes/groovy",files="build.gradle[tags=ad-hoc-task]"]
include::sample[dir="snippets/configurationCache/disallowedTypes/kotlin",files="build.gradle.kts[tags=ad-hoc-task]"]
====
<1> this will be reported as a problem because the `doLast {}` closure is capturing a reference to the `SourceSet`

You still need to fulfil the same requirement, that is not referencing a disallowed type.
Here's how the task declaration above can be fixed:

====
include::sample[dir="snippets/configurationCache/disallowedTypesFixed/groovy",files="build.gradle[tags=ad-hoc-task]"]
include::sample[dir="snippets/configurationCache/disallowedTypesFixed/kotlin",files="build.gradle.kts[tags=ad-hoc-task]"]
====
<1> no more problems reported, the `doLast {}` closure now only captures `classpath` which is of the supported `FileCollection` type

Note that sometimes the disallowed type is indirectly referenced.
For example, you could have a task reference some type from a plugin that is allowed.
That type could reference another allowed type that in turn references a disallowed type.
The hierarchical view of the object graph provided in the HTML reports for problems should help you pinpoint the offender.

[[config_cache:requirements:use_project_during_execution]]
=== Using the `Project` object

A task must not use any `Project` objects at execution time.
This includes calling `Task.getProject()` while the task is running.

Some cases can be fixed in the same way as for <<configuration_cache#config_cache:requirements:disallowed_types, disallowed types>>.

Often, similar things are available on both `Project` and `Task`.
For example if you need a `Logger` in your task actions you should use `Task.logger` instead of `Project.logger`.

Otherwise, you can use <<custom_gradle_types#service_injection,injected services>> instead of the methods of `Project`.

Here's an example of a problematic task type using the `Project` object at execution time:

====
include::sample[dir="snippets/configurationCache/projectAtExecution/groovy",files="build.gradle[tags=task-type]"]
include::sample[dir="snippets/configurationCache/projectAtExecution/kotlin",files="build.gradle.kts[tags=task-type]"]
====
<1> this will be reported as a problem because the task action is using the `Project` object at execution time

The following is how it should be done instead:

====
include::sample[dir="snippets/configurationCache/projectAtExecutionFixed/groovy",files="build.gradle[tags=task-type]"]
include::sample[dir="snippets/configurationCache/projectAtExecutionFixed/kotlin",files="build.gradle.kts[tags=task-type]"]
====
<1> no more problem reported, the injected `FileSystemOperations` service is supported as a replacement for `project.copy {}`

In the same vein, if you encounter the same problem with an ad-hoc task declared in a script as follows:

====
include::sample[dir="snippets/configurationCache/projectAtExecution/groovy",files="build.gradle[tags=ad-hoc-task]"]
include::sample[dir="snippets/configurationCache/projectAtExecution/kotlin",files="build.gradle.kts[tags=ad-hoc-task]"]
====
<1> this will be reported as a problem because the task action is using the `Project` object at execution time

Here's how the task declaration above can be fixed:

====
include::sample[dir="snippets/configurationCache/projectAtExecutionFixed/groovy",files="build.gradle[tags=ad-hoc-task]"]
include::sample[dir="snippets/configurationCache/projectAtExecutionFixed/kotlin",files="build.gradle.kts[tags=ad-hoc-task]"]
====
<1> services can't be injected directly in scripts, we need an extra type to convey the injection point
<2> create an instance of the extra type using `project.object` outside the task action
<3> no more problem reported, the task action references `injected` that provides the `FileSystemOperations` service, supported as a replacement for `project.copy {}`

As you can see above, fixing ad-hoc tasks declared in scripts requires quite a bit of ceremony.
It is a good time to think about extracting your task declaration as a proper task class as shown previously.

The following table shows what APIs or injected service should be used as a replacement for each of the `Project` methods.

[cols="a,a",options="header"]
|===
| Instead of:
| Use:

| `project.rootDir`
| A task input or output property or a script variable to capture the result of using `project.rootDir` to calculate the actual parameter.

| `project.projectDir`
| A task input or output property or a script variable to capture the result of using `project.projectDir` to calculate the actual parameter.

| `project.buildDir`
| A task input or output property or a script variable to capture the result of using `project.buildDir` to calculate the actual parameter.

| `project.name`
| A task input or output property or a script variable to capture the result of using `project.name` to calculate the actual parameter.

| `project.description`
| A task input or output property or a script variable to capture the result of using `project.description` to calculate the actual parameter.

| `project.group`
| A task input or output property or a script variable to capture the result of using `project.group` to calculate the actual parameter.

| `project.version`
| A task input or output property or a script variable to capture the result of using `project.version` to calculate the actual parameter.

| `project.properties`, `project.property(name)`, `project.hasProperty(name)`, `project.getProperty(name)` or `project.findProperty(name)`
| <<configuration_cache#config_cache:requirements:undeclared_gradle_prop_read, Value providers for Gradle properties>>

| `project.logger`
| link:{javadocPath}/org/gradle/api/Task.html#getLogger--[Task.logger]

| `project.provider {}`
| link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#provider-java.util.concurrent.Callable-[ProviderFactory.provider {}]

| `project.file(path)`
| A task input or output property or a script variable to capture the result of using `project.file(file)` to calculate the actual parameter.

| `project.uri(path)`
| A task input or output property or a script variable to capture the result of using `project.uri(path)` to calculate the actual parameter. Otherwise, `File.toURI()` or some other JVM API can be used.

| `project.relativePath(path)`
| link:{javadocPath}/org/gradle/api/file/ProjectLayout.html#getProjectDirectory--[ProjectLayout.projectDirectory].link:{javadocPath}/org/gradle/api/file/Directory.html#file-java.lang.String-[file(path)]

| `project.files(paths)`
| link:{javadocPath}/org/gradle/api/model/ObjectFactory.html#fileCollection--[ObjectFactory.fileCollection()].link:{javadocPath}/org/gradle/api/file/ConfigurableFileCollection.html#from-java.lang.Object...-[from(paths)]

| `project.fileTree(paths)`
| link:{javadocPath}/org/gradle/api/model/ObjectFactory.html#fileTree--[ObjectFactory.fileTree()].link:{javadocPath}/org/gradle/api/file/ConfigurableFileTree.html#from-java.lang.Object-[from(dir)]

| `project.zipTree(path)`
| link:{javadocPath}/org/gradle/api/file/ArchiveOperations.html#zipTree-java.lang.Object-[ArchiveOperations.zipTree(path)]

| `project.tarTree(path)`
| link:{javadocPath}/org/gradle/api/file/ArchiveOperations.html#tarTree-java.lang.Object-[ArchiveOperations.tarTree(path)]

| `project.resources`
| A task input or output property or a script variable to capture the result of using `project.resource` to calculate the actual parameter.

| `project.copySpec {}`
| A task input or output property or a script variable to capture the result of using `project.copySpec {}` to calculate the actual parameter.

| `project.copy {}`
| link:{javadocPath}/org/gradle/api/file/FileSystemOperations.html#copy-org.gradle.api.Action-[FileSystemOperations.copy {}]

| `project.sync {}`
| link:{javadocPath}/org/gradle/api/file/FileSystemOperations.html#sync-org.gradle.api.Action-[FileSystemOperations.sync {}]

| `project.delete {}`
| link:{javadocPath}/org/gradle/api/file/FileSystemOperations.html#delete-org.gradle.api.Action-[FileSystemOperations.delete {}]

| `project.mkdir(path)`
| The Kotlin, Groovy or Java API available to your build logic.

| `project.exec {}`
| link:{javadocPath}/org/gradle/process/ExecOperations.html#exec-org.gradle.api.Action-[ExecOperations.exec {}]

| `project.javaexec {}`
| link:{javadocPath}/org/gradle/process/ExecOperations.html#javaexec-org.gradle.api.Action-[ExecOperations.javaexec {}]

| `project.ant {}`
| link:{javadocPath}/org/gradle/api/Task.html#getAnt--[Task.ant]

| `project.createAntBuilder()`
| link:{javadocPath}/org/gradle/api/Task.html#getAnt--[Task.ant]

|===

[[config_cache:requirements:task_access]]
=== Accessing a task instance from another instance

Tasks should not directly access the state of another task instance.
Instead, tasks should be connected using <<lazy_configuration#working_with_task_dependencies_in_lazy_properties, inputs and outputs relationships>>.

Note that this requirement makes it unsupported to write tasks that configure other tasks at execution time.

[[config_cache:requirements:build_listeners]]
=== Using build listeners

Plugins and build scripts must not register any build listeners.
That is listeners registered at configuration time that get notified at execution time.
For example a `BuildListener` or a `TaskExecutionListener`.

These should be replaced by <<build_services#build_services,build services>>, registered to receive information about <<build_services#operation_listener, task execution>> if needed.

[[config_cache:requirements:undeclared_gradle_prop_read]]
=== Undeclared reading of Gradle properties

Plugins and build scripts should not read Gradle properties directly at configuration time.
Instead, these Gradle properties must be declared as a potential build configuration input by using the value supplier APIs.

This problem is caused by build logic similar to this:

====
include::sample[dir="snippets/valueProviders/gradlePropsDont/groovy",files="build.gradle[]"]
include::sample[dir="snippets/valueProviders/gradlePropsDont/kotlin",files="build.gradle.kts[]"]
====

To fix this problem, read Gradle properties using link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#gradleProperty-java.lang.String-[providers.gradleProperty()] instead:

====
include::sample[dir="snippets/valueProviders/gradlePropsDo/groovy",files="build.gradle[]"]
include::sample[dir="snippets/valueProviders/gradlePropsDo/kotlin",files="build.gradle.kts[]"]
====

In general, you should avoid reading the value of Gradle properties at configuration time, to avoid invalidating configuration cache entries when the Gradle property value changes.
Instead, you can connect the `Provider` returned by link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#gradleProperty-java.lang.String-[providers.gradleProperty()] to task properties.

[[config_cache:requirements:undeclared_sys_prop_read]]
=== Undeclared reading of system properties

Plugins and build scripts should not read system properties directly using the Java APIs at configuration time.
Instead, these system properties must be declared as a potential build configuration input by using the value supplier APIs.

This problem is caused by build logic similar to this:

====
include::sample[dir="snippets/valueProviders/sysPropsDont/groovy",files="build.gradle[]"]
include::sample[dir="snippets/valueProviders/sysPropsDont/kotlin",files="build.gradle.kts[]"]
====

To fix this problem, read system properties using link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#systemProperty-java.lang.String-[providers.systemProperty()] instead:

====
include::sample[dir="snippets/valueProviders/sysPropsDo/groovy",files="build.gradle[]"]
include::sample[dir="snippets/valueProviders/sysPropsDo/kotlin",files="build.gradle.kts[]"]
====

In general, you should avoid reading the value of system properties at configuration time, to avoid invalidating configuration cache entries when the system property value changes.
Instead, you can connect the `Provider` returned by link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#systemProperty-java.lang.String-[providers.systemProperty()] to task properties.

[[config_cache:requirements:undeclared_env_var_read]]
=== Undeclared reading of environment variables

Plugins and build scripts should not read environment variables directly using the Java APIs at configuration time.
Instead, declare environment variables as potential build configuration inputs using the value supplier APIs.

This problem is caused by build logic similar to this:

====
include::sample[dir="snippets/valueProviders/envVarsDont/groovy",files="build.gradle[]"]
include::sample[dir="snippets/valueProviders/envVarsDont/kotlin",files="build.gradle.kts[]"]
====

To fix this problem, read environment variables using link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#environmentVariable-java.lang.String-[providers.environmentVariable()] instead:

====
include::sample[dir="snippets/valueProviders/envVarsDo/groovy",files="build.gradle[]"]
include::sample[dir="snippets/valueProviders/envVarsDo/kotlin",files="build.gradle.kts[]"]
====

In general, you should avoid reading the value of environment variables at configuration time, to avoid invalidating configuration cache entries when the environment variable value changes.
Instead, you can connect the `Provider` returned by link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#environmentVariable-java.lang.String-[providers.environmentVariable()] to task properties.

[[config_cache:requirements:undeclared_file_read]]
=== Undeclared reading of files

Plugins and build scripts should not read files directly using the Java, Groovy or Kotlin APIs at configuration time.
Instead, declare files as potential build configuration inputs using the value supplier APIs.

This problem is caused by build logic similar to this:

====
include::sample[dir="snippets/valueProviders/fileContentsDont/groovy",files="build.gradle[]"]
include::sample[dir="snippets/valueProviders/fileContentsDont/kotlin",files="build.gradle.kts[]"]
====

To fix this problem, read files using link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#fileContents-org.gradle.api.file.RegularFile-[providers.fileContents()] instead:

====
include::sample[dir="snippets/valueProviders/fileContentsDo/groovy",files="build.gradle[]"]
include::sample[dir="snippets/valueProviders/fileContentsDo/kotlin",files="build.gradle.kts[]"]
====

In general, you should avoid reading files at configuration time, to avoid invalidating configuration cache entries when the file content changes.
Instead, you can connect the `Provider` returned by link:{javadocPath}/org/gradle/api/provider/ProviderFactory.html#fileContents-org.gradle.api.file.RegularFile-[providers.fileContents()] to task properties.

[[config_cache:not_yet_implemented]]
== Not yet implemented

Support for using configuration caching with certain Gradle features is not yet implemented.
Support for these features will be added in later Gradle releases.

[[config_cache:not_yet_implemented:build_scan]]
=== Build scan support

Build scan functionality with configuration caching enabled requires Gradle Enterprise plugin version 3.4 or later.
When using an earlier version, build scan publishing will be automatically disabled when configuration caching is used.

[[config_cache:not_yet_implemented:sharing]]
=== Sharing the configuration cache

The configuration cache is currently stored locally only.
It can be reused by hot or cold local Gradle daemons.
But it can't be shared between developers or CI machines.

See link:{gradle-issues}13510[gradle/gradle#13510].

[[config_cache:not_yet_implemented:normalization]]
=== Custom input normalization

Custom <<more_about_tasks#sec:configure_input_normalization, input normalization>> is not captured when using the configuration cache.
If your build has configuration for input normalization, i.e. `normalization { }`, it will be ignored, no problem will be reported.
Builds reusing the configuration cache might see build cache misses but will stay reliable.

See link:{gradle-issues}13706[gradle/gradle#13706].

[[config_cache:not_yet_implemented:composite_builds]]
=== Composite builds

When using the configuration cache on a <<composite_builds#composite_builds,composite build>> a problem will be reported.
If you <<configuration_cache#config_cache:usage:ignore_problems,ignore problems>> then the included builds will be skipped when reusing the configuration cache.

See link:{gradle-issues}13503[gradle/gradle#13503].

[[config_cache:not_yet_implemented:source_dependencies]]
=== Source dependencies

Support for link:https://blog.gradle.org/introducing-source-dependencies[source dependencies] is not yet implemented.
With the configuration cache enabled, no problem will be reported and the build will fail.

See link:{gradle-issues}13506[gradle/gradle#13506].

[[config_cache:not_yet_implemented:testkit_build_with_java_agent]]
=== Using a Java agent with builds run using TestKit

When running builds using <<test_kit#test_kit, TestKit>>, the configuration cache can interfere with Java agents, such as the Jacoco agent, that are applied to these builds.

[[config_cache:not_yet_implemented:java_serialization]]
=== Java Object Serialization

Gradle allows objects that support the link:https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html[Java Object Serialization] protocol to be stored in the configuration cache.

The implementation is currently limited to serializable classes that implement the `java.io.Serializable` interface
and define one of the following combination of methods:

- a `writeObject` method combined with a `readObject` method to control exactly which information to store;
- a `writeObject` method with no corresponding `readObject`; `writeObject` must eventually call `ObjectOutputStream.defaultWriteObject`;
- a `readObject` method with no corresponding `writeObject`; `readObject` must eventually call `ObjectInputStream.defaultReadObject`;
- a `writeReplace` method to allow the class to nominate a replacement to be written;
- a `readResolve` method to allow the class to nominate a replacement for the object just read;

The following _Java Object Serialization_ features are **not** supported:

- serializable classes implementing the `java.io.Externalizable` interface; objects of such classes are discarded by the configuration cache during serialization and reported as problems;
- the `serialPersistentFields` member to explicitly declare which fields are serializable; the member, if present, is ignored; the configuration cache considers all but `transient` fields serializable;
- the following methods of `ObjectOutputStream` are not supported and will throw `UnsupportedOperationException`:
** `reset()`, `writeFields()`, `putFields()`, `writeChars(String)`, `writeBytes(String)` and `writeUnshared(Any?)`.

- the following methods of `ObjectInputStream` are not supported and will throw `UnsupportedOperationException`:
** `readLine()`, `readFully(ByteArray)`, `readFully(ByteArray, Int, Int)`, `readUnshared()`, `readFields()`, `transferTo(OutputStream)` and `readAllBytes()`.
- validations registered via `ObjectInputStream.registerValidation` are simply ignored;
- the `readObjectNoData` method, if present, is never invoked;

See link:{gradle-issues}13588[gradle/gradle#13588].
