// Copyright (C) 2024 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[gradle_optimizations]]
= Incremental Builds and Build Caching Basic

Gradle uses two main features to reduce build time: *incremental builds* and *build caching*.

image::gradle-basic-8.png[]

== Task Outcome Labels

When you run a Gradle build with verbose mode turned on, each task prints a short outcome label that describes what happened during execution.
These labels help you understand Gradle’s behavior and performance optimizations like incremental build and build caching:

[source,text]
----
> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :jar FROM-CACHE
> Task :test SKIPPED
> Task :publish
----

[cols="1,3", options="header"]
|===
| Task Label                | Meaning

| `UP-TO-DATE`         | The task's inputs and outputs haven’t changed since the last run, so it was skipped.

| `FROM-CACHE`         | The task was skipped and its outputs were restored from the local or remote build cache.

| `NO-SOURCE`          | The task had no source files to process (e.g., no Java files to compile), so it was skipped.

| `SKIPPED`            | The task was not executed due to a condition (e.g., only-if rule or command-line flags).

|                      | The task ran normally and produced outputs.

| `FAILED`             | The task ran but encountered an error.
|===

== Incremental Builds

An *incremental build* is a build that avoids running tasks whose inputs have not changed since the previous build.
Re-executing such tasks is unnecessary if they would only re-produce the same output.

For incremental builds to work, tasks must define their inputs and outputs.
Gradle will determine whether those input or outputs have changed at build time.
If they have changed, Gradle will execute the task.
Otherwise, it will skip execution.

Incremental builds are always enabled, and the best way to see them in action is to turn on _verbose mode_.
With verbose mode, each task state is labeled during a build:

[source,bash]
----
$ ./gradlew compileJava --console=verbose
----
[source,text]
----
> Task :buildSrc:generateExternalPluginSpecBuilders UP-TO-DATE
> Task :buildSrc:extractPrecompiledScriptPluginPlugins UP-TO-DATE
> Task :buildSrc:compilePluginsBlocks UP-TO-DATE
> Task :buildSrc:generatePrecompiledScriptPluginAccessors UP-TO-DATE
> Task :buildSrc:generateScriptPluginAdapters UP-TO-DATE
> Task :buildSrc:compileKotlin UP-TO-DATE
> Task :buildSrc:compileJava NO-SOURCE
> Task :buildSrc:compileGroovy NO-SOURCE
> Task :buildSrc:pluginDescriptors UP-TO-DATE
> Task :buildSrc:processResources UP-TO-DATE
> Task :buildSrc:classes UP-TO-DATE
> Task :buildSrc:jar UP-TO-DATE
> Task :list:compileJava UP-TO-DATE
> Task :utilities:compileJava UP-TO-DATE
> Task :app:compileJava UP-TO-DATE

BUILD SUCCESSFUL in 374ms
12 actionable tasks: 12 up-to-date
----

When you run a task that has been previously executed and hasn't changed, then `UP-TO-DATE` is printed next to the task.

TIP: To permanently enable verbose mode, add `org.gradle.console=verbose` to your `gradle.properties` file.

== Build Caching

Incremental Builds are a great optimization that helps avoid work already done.
If a developer continuously changes a single file, there is likely no need to rebuild all the other files in the project.

However, what happens when the same developer switches to a new branch created last week?
The files are rebuilt, even though the developer is building something that has been built before.

This is where a *build cache* is helpful.

The build cache stores previous build results and restores them when needed.
It prevents the redundant work and cost of executing time-consuming and expensive processes.

When the build cache has been used to repopulate the local directory, the tasks are marked as `FROM-CACHE`:

[source,bash]
----
$ ./gradlew compileJava --build-cache
----
[source,text]
----
> Task :buildSrc:generateExternalPluginSpecBuilders UP-TO-DATE
> Task :buildSrc:extractPrecompiledScriptPluginPlugins UP-TO-DATE
> Task :buildSrc:compilePluginsBlocks UP-TO-DATE
> Task :buildSrc:generatePrecompiledScriptPluginAccessors UP-TO-DATE
> Task :buildSrc:generateScriptPluginAdapters UP-TO-DATE
> Task :buildSrc:compileKotlin UP-TO-DATE
> Task :buildSrc:compileJava NO-SOURCE
> Task :buildSrc:compileGroovy NO-SOURCE
> Task :buildSrc:pluginDescriptors UP-TO-DATE
> Task :buildSrc:processResources UP-TO-DATE
> Task :buildSrc:classes UP-TO-DATE
> Task :buildSrc:jar UP-TO-DATE
> Task :list:compileJava FROM-CACHE
> Task :utilities:compileJava FROM-CACHE
> Task :app:compileJava FROM-CACHE

BUILD SUCCESSFUL in 364ms
12 actionable tasks: 3 from cache, 9 up-to-date
----

Once the local directory has been repopulated, the next execution will mark tasks as `UP-TO-DATE` and not `FROM-CACHE`.

The build cache allows you to share and reuse unchanged build and test outputs across teams.
This speeds up local and CI builds since cycles are not wasted re-building binaries unaffected by new code changes.

[.text-right]
**Next Step:** <<plugin_basics.adoc#plugin_basics,Learn about Plugins>> >>
