Speeding Up Gradle Builds with the Build Cache: Configuration, Mechanics, and Pitfalls
Enable Gradle's build cache to reuse task outputs across clean builds and machines. Covers local and remote cache setup, cache keys, verification, and common pitfalls.
19 Mar 2026, 14:59 UTC

If your Gradle builds recompile everything after every clean, or every CI job starts from zero, the build cache is the fix. Unlike incremental builds, which only skip work when the build/ directory still exists, the build cache stores task outputs keyed by their inputs and restores them even after a clean checkout — and, with a remote cache, even on machines that never ran the task.
What the cache actually does
Gradle's incremental build compares timestamps and file hashes against the previous run in the same workspace. Delete build/ and that information is gone. The build cache works differently: when a cacheable task finishes, Gradle packs its outputs and stores them under a hash key computed from the task's implementation classpath, its declared input properties, and the content hashes of its input files. On a later run — anywhere — Gradle computes the same key, finds the entry, and unpacks the outputs instead of executing the task. You'll see FROM-CACHE next to the task name in the console.
There are two layers. The local cache lives in ~/.gradle/caches/build-cache-1 and benefits a single developer across cleans and branch switches. The remote cache is an HTTP server (Gradle's official node, or a simple nginx/S3-backed store) shared by the team and CI, so one machine's compile warms everyone else's build.
A working configuration
Enable caching in gradle.properties (project root or ~/.gradle/gradle.properties):
org.gradle.caching=true
Then configure a remote cache in settings.gradle:
buildCache {
local {
enabled = true
}
remote(HttpBuildCache) {
url = 'https://cache.example.com/cache/'
push = System.getenv('CI') != null
credentials {
username = System.getenv('CACHE_USER')
password = System.getenv('CACHE_PASSWORD')
}
}
}
The push = System.getenv('CI') != null line is a deliberate decision: only CI pushes to the shared cache, while developers only pull. This keeps the remote cache filled by a controlled, clean environment and avoids poisoning it with outputs from a developer's dirty workspace.
Most built-in JVM tasks (compileJava, compileKotlin, test) are already cacheable. Custom tasks need opt-in: annotate the task class with @CacheableTask and declare every input (@Input, @InputFiles, @Classpath) and output (@OutputDirectory, @OutputFile) precisely. Anything the task reads that isn't declared is an input Gradle can't see — and a source of stale cache hits.
How to verify it works
Run from the project root (no special permissions needed):
./gradlew clean assemble
./gradlew clean assemble
The second run should show FROM-CACHE on compilation and packaging tasks, even though clean deleted the outputs. If everything shows UP-TO-DATE instead, you didn't actually clean; if tasks re-execute, check the cache key inputs. For a remote cache, a second machine or a wiped ~/.gradle/caches/build-cache-1 directory is the real test.
Limits and common mistakes
- Non-deterministic inputs kill hit rates. Timestamps embedded in outputs, absolute paths in input properties, or environment-dependent values produce different keys per machine. Use
PathSensitivity.RELATIVEon file inputs and normalize paths. - Under-declared inputs cause stale hits. If a task reads a config file that isn't declared as an input, changing that file won't change the key, and Gradle will restore an outdated output. When in doubt, declare more inputs, not fewer.
- Tiny tasks may not be worth caching remotely. Network round-trips can cost more than re-running a 50 ms task. You can disable remote caching per task type if profiling shows it.
- Overlapping outputs between tasks make cache restoration unreliable; keep each task's outputs in its own directory.
Version note: behavior described matches Gradle 7.x/8.x; the HttpBuildCache API and org.gradle.caching property are stable there. Confirm against your version's release notes before relying on remote-cache push authentication details.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.