# Gradle on CI / CD Systems

version 9.8.0-milestone-2

Gradle integrates with many Continuous Integration (CI) and Continuous Delivery (CD) systems.

The pages in this section provide recipes and best practices for configuring popular CI platforms to build Gradle projects efficiently.

## General CI best practices

The best configuration for a CI build depends on how the build agent is managed. The recommendations in this section assume that the build is invoked with the Gradle Wrapper and that the CI job is responsible for producing a reproducible result.

### Do not run `clean` by default

Running `clean` removes local outputs and prevents the build from benefiting from incremental execution in the same workspace. It is usually unnecessary to run an ordinary CI build when the workspace is isolated, and the build outputs are controlled by Gradle.

Run `clean` when the job intentionally validates a clean checkout, when outputs from an earlier build are not trusted, or when the Build Cache workflow specifically requires a clean producer build. If a build requires `clean` to succeed, investigate undeclared inputs or outputs rather than treating `clean` as a general fix.

### Use the Gradle Wrapper

Use `./gradlew` on Unix-like systems and `gradlew.bat` on Windows instead of relying on a Gradle installation provided by the CI image. The Wrapper selects the Gradle version committed to the project and downloads the distribution when it is not already available. See The Gradle Wrapper for details.

### Use the Gradle Daemon when it matches the agent lifecycle

The Gradle Daemon is enabled by default and can reduce startup time by reusing a long-lived JVM and its caches. It is generally useful when an agent runs multiple Gradle invocations or is reused between jobs. See The Gradle Daemon for configuration and troubleshooting.

On a disposable agent, the daemon process offers little benefit once the job ends. It is still safe to use the default behavior, but avoid relying on the daemon to preserve state for a later job. If a CI environment requires every process to exit before the job finishes, use `--no-daemon` for that job and verify the resulting performance and resource usage.

Do not use a shared `GRADLE_USER_HOME` concurrently from unrelated jobs. Gradle caches and daemon state are designed to be used by compatible processes, not as a general-purpose shared workspace. Prefer a CI cache action or a remote Build Cache to move state between jobs safely.

### Enable the Configuration Cache when the build is compatible

The Configuration Cache can avoid repeating the configuration phase on subsequent invocations. Enable it for a CI build with:

    ./gradlew --configuration-cache <tasks>

To enable it successfully, follow the steps at Enabling and Configuring the Configuration Cache.

### Use the Build Cache for reusable task outputs

The Build Cache reuses task outputs when the task inputs and implementation are compatible. It differs from the Configuration Cache. The Build Cache reuses work produced by tasks, whereas the Configuration Cache reuses the configured build state.

For a shared remote Build Cache, a common pattern is:

- CI builds populate the cache after validating their outputs.

- Other CI jobs and developer builds read from the remote cache.

- Cache writes are restricted to trusted jobs when the cache is shared across teams.

Enable the cache for a job with `--build-cache` or configure `org.gradle.caching=true` in `gradle.properties`:

    ./gradlew --build-cache <tasks>

To enable it successfully, follow the steps at Enabling the Build Cache. See Build Cache Use Cases for real-world CI scenarios and Common Caching Problems before diagnosing a cache miss.

### Choose cache strategy by agent type

Beyond the general recommendations above, the agent lifecycle determines which additional optimizations are available. CI agents fall into two broad categories: persistent (long-lived, shared across jobs) and ephemeral (fresh for every job).

#### Persistent (long-lived) agents

Persistent agents run multiple jobs over time. They can benefit from the Daemon and local caches, but they need regular workspace cleanup, size limits on the Gradle User Home, and isolation between concurrent jobs.

| Do not let one job’s project properties, initialization scripts, credentials, or generated outputs affect another job.

For persistent-agent optimizations, see:

- Configuring cache cleanup — rely on Gradle’s automatic cleanup to bound the Gradle User Home and rotate old entries, rather than letting it grow without limit.

- File System Watching — a long-lived daemon can watch the filesystem to speed up input tracking.

- Improving performance — general build performance guidance that persistent agents can carry across jobs.

#### Ephemeral agents

Ephemeral agents are deleted after a job. They benefit from a CI cache restore, a remote Build Cache, and a correctly scoped Gradle User Home, but they cannot benefit from a Daemon or local task outputs after the job ends.

When configuring a CI provider’s cache action to persist parts of the Gradle User Home between jobs, include only the paths that are safe to share and that improve reuse.

Include the following:

- `caches/modules-2` — downloaded dependency metadata and artifacts.

- `caches/<gradle-version>/kotlin-dsl` and `caches/<gradle-version>/scripts` — compiled build-script state.

- `wrapper/dists/<gradle-version>` — the Gradle distribution downloaded by the Wrapper, if the CI image does not already ship it.

Exclude the following unless the CI setup explicitly requires them and the security and correctness implications are understood:

- Credentials or any secret material Gradle reads from environment variables, `gradle.properties`, or an init script.

- Initialization scripts (`init.d/`) — treat them as build inputs and provide them per-job.

- Logs and notification state — job-local, not portable, and can leak information across jobs.

- Daemon state (`daemon/`) — the Daemon does not resume across agent lifetimes.

Key the cache by the axes that affect resolution and compilation: operating system, architecture, JDK, Gradle Wrapper version, and the files that describe your dependencies (`build.gradle*`, `settings.gradle*`, `gradle-wrapper.properties`, and any version catalog). Sharing a cache between incompatible operating systems, architectures, JDKs, or Gradle versions can reduce hit rates and cause cache restoration or file-locking problems.

See Cache layout for the full directory structure.

For more ephemeral-agent optimizations, see the Gradle on Ephemeral CI blog series.

### Diagnose slow or unreliable CI builds

When a CI build is slow, record whether the cause is Daemon startup, dependency downloads, build-script compilation, configuration, task execution, or cache misses. Useful starting points are:

- `--info` for additional execution and cache information

- `--scan` when build scans are enabled for the project

- the Configuration Cache report when configuration-cache problems are reported

- the Build Cache debugging guidance when task outputs are not reused

- the CI provider’s cache and workspace logs

Compare cold and warm runs separately. A cache restore can improve one phase while adding overhead to another, so measure the complete CI job rather than only the Gradle command.

## Recipes

The following recipes walk through configuring Gradle for specific CI systems:

- GitHub Actions

- GitLab CI

- Jenkins

- TeamCity

- CircleCI

- Travis CI

- Docker Images