Build Cache and Performance
Why Gradle skips work: up-to-date checks, the local and remote build cache, and the configuration cache, plus parallelism and how to measure a build honestly. It comes up in every conversation about shrinking CI time.
on this pageshowhide
explore
- Incremental Work Avoidance25 questions
- Up-To-Date Checks5 questions
- Incremental Tasks With InputChanges5 questions
- Path Sensitivity Normalization5 questions
- Classpath Normalization5 questions
- Declaring Inputs And Outputs5 questions
- Build Cache30 questions
- Enabling The Build Cache5 questions
- Local Build Cache5 questions
- Remote HttpBuildCache5 questions
- CI Push/Pull And Seeding5 questions
- Cacheable Tasks5 questions
- Cache Key And Hit Diagnosis5 questions
- Configuration Cache30 questions
- Enabling Configuration Cache5 questions
- Serializing The Task Graph5 questions
- Incompatible APIs And Migration5 questions
- Problems Report And HTML5 questions
- BuildService For Shared State5 questions
- Build Features and Stable Config Cache5 questions
- Parallelism And Daemon Performance35 questions
- Parallel Project Execution5 questions
- Worker Count And Worker API5 questions
- Project Isolation5 questions
- Daemon Reuse For Speed5 questions
- JVM Warmup And Daemon Heap5 questions
- Configuration On Demand5 questions
- File System Watching (VFS)5 questions
- Measurement And Profiling26 questions
- Build Scans5 questions
- Scan Timeline And Cache Insights6 questions
- Profile HTML Report5 questions
- Configuration vs Execution Time5 questions
- Dry Run And Task Timing Flags5 questions
questions
146 · 5 sectionsWhat does the @Classpath input annotation do, and why would you use it instead of @InputFiles for a collection of jars?
basics
~10 s@Classpath marks a task input as a classpath: Gradle hashes the file contents in order but ignores file names and paths. @InputFiles treats each file's absolute path as significant, so it over-invalidates.
What are task inputs and outputs in Gradle, and how do you declare them for an ad-hoc task using the runtime API?
basics
~10 sInputs are the files/values a task reads; outputs are what it produces. For ad-hoc tasks you declare them at runtime via task.inputs.file()/dir()/property() and task.outputs.file()/dir() so Gradle can track changes.
What does it mean when Gradle marks a task as UP-TO-DATE, and how does Gradle decide that?
basics
~10 sUP-TO-DATE means Gradle skipped the task because its inputs and outputs haven't changed since the last run. Gradle compares snapshots of the declared inputs/outputs; if they match, it reuses the previous result.
How does @CompileClasspath differ from @Classpath, and how does ABI-based fingerprinting help avoid recompilation?
basics
~10 s@CompileClasspath fingerprints only the public API (ABI) of jars — class/method/field signatures — ignoring method bodies, private members and resources. So changing only an implementation detail upstream doesn't invalidate downstream compilation.
How do you configure runtime classpath normalization to ignore a volatile file like build-info.properties, and why is it needed?
basics
~10 sIn settings.gradle(.kts) use normalization { runtimeClasspath { ignore 'build-info.properties' } }. It strips that file from the runtime-classpath fingerprint so a volatile, build-stamped entry doesn't cause needless cache misses or out-of-date tasks.
What does it mean for a Gradle task to be cacheable, and what is the minimum required to make a task's outputs reusable from the build cache?
basics
~10 sA cacheable task can store its outputs in the build cache and restore them later instead of re-running. It needs the @CacheableTask annotation and fully declared inputs and outputs.
How do you turn the Gradle build cache on, and what is the simplest way to make it the default for everyone on the project?
basics
~10 sSet org.gradle.caching=true in the project's gradle.properties so it is on for every build and every developer, or pass --build-cache on a single command to enable it just for that run.
When you run a Gradle build, what does the FROM-CACHE outcome next to a task mean, and how does it differ from UP-TO-DATE and executed?
basics
~10 sFROM-CACHE means Gradle restored the task's outputs from the build cache instead of running it. UP-TO-DATE means outputs were already on disk and unchanged. Executed means the task actually ran.
Where does Gradle's local build cache store its entries by default, and what does it actually hold?
basics
~10 sBy default the local build cache lives in ~/.gradle/caches/build-cache-1. It stores the outputs of cacheable tasks keyed by a hash, so a later build can reuse them instead of re-running the task.
Where in a Gradle project do you configure the push/pull split for the remote build cache, and at what point in the build lifecycle does that configuration take effect?
basics
~20 sIn settings.gradle(.kts), inside the buildCache { remote<HttpBuildCache> { ... } } block. It takes effect very early — during settings evaluation, before any project is configured — because the cache must be ready before tasks run.
How do you turn on Gradle's configuration cache for a build, and what are the two main ways to do it?
basics
~10 sPass --configuration-cache on the command line for a single run, or set org.gradle.configuration-cache=true in gradle.properties to enable it persistently for every build.
When you enable the configuration cache and a build reports problems, Gradle prints a link to a configuration-cache-report.html file. What is in that report and how do you use it?
basics
~20 sIt is an HTML report Gradle generates listing every configuration-cache problem found, grouped by category, with the task or input that caused each one and a stack-trace-like location so you can find and fix the offending code.
When the configuration cache is enabled, what does Gradle serialize and store at the end of the configuration phase, and what does that let it skip on the next build?
basics
~20 sGradle serializes the resolved task graph — the tasks to run plus their configured state — to disk. On a cache hit it loads that snapshot and skips the whole configuration phase, going straight to executing tasks.
Walk through the difference between configurationCache.requested and configurationCache.active. Give a concrete scenario where requested is true but active is false.
basics
~20 srequested means the user asked for the configuration cache; active means it is actually operating. They diverge when, for example, the user sets it in gradle.properties but passes --no-configuration-cache on the command line — requested true, active false.
What is the BuildFeatures service in Gradle, and how does a plugin obtain it to learn whether the configuration cache is in play?
basics
~10 sBuildFeatures is a Gradle service exposing whether opt-in features like the configuration cache are requested and active. A plugin gets it via gradle.serviceOf<BuildFeatures>() (or constructor injection) and reads configurationCache.requested / .active.
What is the Gradle Daemon and why does reusing a warm daemon make builds faster?
basics
~10 sThe daemon is a long-lived background JVM that runs your builds. Reusing a warm one skips JVM startup, class loading, and JIT warmup, so subsequent builds start much faster.
Why is the second Gradle build in a session usually noticeably faster than the very first one, even when nothing about the project has changed?
basics
~10 sGradle runs in a long-lived background JVM (the daemon). The first build pays JVM startup and HotSpot JIT warmup; later builds reuse that already-warm JVM, so they skip those costs and run faster.
What does Gradle's --max-workers flag (or org.gradle.workers.max property) control, and what is its default value?
basics
~10 sIt caps the maximum number of work items Gradle runs concurrently across the whole build — parallel tasks, test forks, Worker API jobs. It defaults to the number of CPU processors Gradle detects.
How do you enable parallel project execution in Gradle, and what exactly does it parallelize?
basics
~10 sPass --parallel on the command line, or set org.gradle.parallel=true in gradle.properties. Gradle then runs tasks from different projects concurrently using the daemon's worker threads, instead of one project at a time.
What is Gradle's File System Watching (VFS), and what problem does it solve between consecutive builds?
basics
~10 sGradle keeps an in-memory Virtual File System of file metadata and listens to OS file-change events. Between builds it retains that data so it doesn't re-read every file, making up-to-date checks faster.
What is a Gradle Build Scan, and how do you publish one from a build?
basics
~10 sA Build Scan is a shareable web report of a build's results. You publish one by adding --scan to any Gradle command; Gradle uploads the data and prints a scan URL.
What is the difference between Gradle's configuration phase and execution phase, and why does the distinction matter when a build feels slow?
basics
~20 sConfiguration builds the task graph by evaluating build scripts; execution runs the selected tasks' actions. A build can be slow because the graph takes long to build (configuration) or because the tasks themselves take long (execution).
What does the --dry-run flag do when you run a Gradle build, and when would you use it?
basics
~10 s--dry-run makes Gradle print the ordered list of tasks it WOULD run for your requested goal, without actually executing any of them. It's a safe way to preview the task graph.
What is the Gradle --profile HTML report and how do you generate one?
basics
~10 sPass --profile to a build (e.g. ./gradlew build --profile). Gradle writes a self-contained HTML report to build/reports/profile/profile-<timestamp>.html showing where build time was spent.
You've published a Build Scan for a slow build. How do you use the Timeline tab to find the single slowest task and understand why the overall build took so long?
basics
~10 sOpen the Build Scan's Timeline tab, sort tasks by duration (longest first), and read the top entry. It shows each task's wall-clock time so you can see which task dominated the build.