Configuring GitHub Actions


This guide shows you how to integrate the Artifact Cache CLI into your GitHub Actions workflows.

There are two supported ways to do this:

  • The Develocity Artifact Cache GitHub Action (repository) is the officially supported and recommended path. It wraps the Artifact Cache CLI, restores the cache before your build, and stores it afterward, with a single step.

  • The manual CLI setup downloads and drives the CLI yourself. Use it on air-gapped or restricted-network runners, when your organization does not permit third-party GitHub Actions, or when you need control beyond the Action’s inputs.

Prerequisites

Before you begin, ensure you have:

See System Requirements for complete details.

Disabling Conflicting Cache Actions

The Artifact Cache provides complete caching functionality. Disable caching in these GitHub Actions to prevent conflicts:

setup-gradle (gradle/actions/setup-gradle)

Apply it before the Artifact Cache Action and disable its Gradle User Home caching. With gradle/actions 6.4.0 or newer, set cache-provider: external, which keeps the job summary accurate by reporting that caching is handled externally rather than turned off; on older versions, set cache-disabled: true. Ordering matters: setup-gradle establishes the Gradle User Home and exports GRADLE_USER_HOME, which the Artifact Cache CLI auto-detects, so running it first ensures the cache is restored into and stored from the Gradle User Home your build uses. If you do not use setup-gradle, the CLI falls back to the default Gradle User Home (~/.gradle) that ./gradlew uses, so the basic template needs no extra configuration; this coordination matters only when a custom GRADLE_USER_HOME is set.

Setup Java (actions/setup-java)

Don’t enable caching - omit the cache parameter.

Cache Action (actions/cache)

Don’t use for Gradle or Maven dependencies. See examples for what to avoid.

Using the GitHub Action

The gradle/develocity-artifact-cache-github-action Action is the officially supported way to run the Artifact Cache CLI in GitHub Actions. It restores the cache in its main step, runs your build, and stores the cache in a post step after a successful build, so you do not write the restore and store steps yourself. By default it downloads the CLI from the public Develocity host, so you do not need to host the binary to get started.

When develocity-url addresses a Develocity Edge node running version 2.3.0 or later, the Action downloads the CLI from that Edge node instead, using the short-lived token it already exchanged for the cache restore as the bearer credential. An explicit cli-repository value always wins over the Edge node, so set it to skip this detection and download from your own mirror instead.

The Action targets one Develocity endpoint: set develocity-url to reach a Develocity server (passed to the CLI as --dv-server), or develocity-edge-url to target a Develocity Edge directly (--dv-edge). Provide exactly one (they are mutually exclusive), and whichever you set also identifies the host for the access key and short-lived-token exchange.

Cache activity is best-effort: a restore or store problem is surfaced as a warning, never a build failure. After the run, the Action adds a single cache-activity table to the GitHub job summary, with a row for the restore and, when it runs, the store. Gradle and Maven builds also surface cache metrics in their Build Scan.

GitHub Actions job summary listing Restore and Store rows with outcome
GitHub Actions Job Summary for the Artifact Cache Action

The Action runs the Artifact Cache CLI under Java 21 (a minimum floor). On GitHub-hosted runners it resolves a suitable JDK automatically from the pre-set JAVA_HOME_* variables, so no setup-java step is required for the Action itself. It is supported on GitHub-hosted Linux, macOS, and Windows runners, and on self-hosted Linux runners. The examples below add actions/setup-java to provide the JDK your build runs on.

Storing the Access Key

In your GitHub repository settings, navigate to Settings > Secrets and variables > Actions and add a DEVELOCITY_ACCESS_KEY secret.

The develocity-access-key input takes the key in <hostname>=<key_value> form, matching the DEVELOCITY_ACCESS_KEY format used by the DV build agents and setup-gradle; a bare key value is not accepted. The Action uses the entry for the chosen endpoint host (whichever of develocity-url or develocity-edge-url is set). It is the only key source: the Action does not read the DEVELOCITY_ACCESS_KEY environment variable or local key files.

The Action exchanges this long-lived key for a short-lived Develocity token, handing it to the Artifact Cache CLI through a private, subprocess-scoped environment variable. It uses that token for its own cache restore and store and, when it downloads the CLI from a Develocity Edge node, as the bearer credential for that download. It does not set DEVELOCITY_ACCESS_KEY for other steps, so neither the long-lived key nor the token is propagated to the rest of the workflow. Steps that need to authenticate with Develocity (for example, to publish a Build Scan) should obtain their own token; gradle/actions/setup-gradle performs the same exchange and exports it for Gradle builds. The token lasts two hours by default; raise develocity-token-expiry only if a build could run long enough for the token to expire before the post-step store.

The resolved key is masked in the workflow log. Prefer an access key scoped to only the servers and permissions it needs.

Authenticating With an OIDC Token

Requires Develocity 2026.3 or later, with a workload identity rule configured for your CI provider. See Workload Identity.

As an alternative to a long-lived DEVELOCITY_ACCESS_KEY secret, a workflow can mint a short-lived OIDC token from GitHub’s OIDC provider (see the GitHub Actions OpenID Connect documentation) and pass it to develocity-access-key in place of the access key value. Develocity validates the token against the issuer, audience, and claim requirements configured on the matching workload identity rule. When you use an OIDC token, you no longer need to store an access key as a GitHub Actions secret.

Grant the job id-token: write permission, mint the token with actions/github-script, mask it, and expose it as a step output in host-qualified «server host name»=«token» form:

name: Artifact Cache with OIDC
on: push
permissions:
  id-token: write
  contents: read
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v7

      - name: Get GitHub OIDC Workload Identity token
        id: dv-token
        uses: actions/github-script@v7
        with:
          script: |
            const token = await core.getIDToken('https://develocity.example.com')
            core.setSecret(token)
            core.setOutput('key', `develocity.example.com=${token}`)

      - name: Develocity Artifact Cache
        uses: gradle/develocity-artifact-cache-github-action@v1
        with:
          develocity-url: https://develocity.example.com
          develocity-access-key: ${{ steps.dv-token.outputs.key }}

To mint the token without actions/github-script, replace the mint step with a curl request to GitHub’s OIDC endpoint, using the ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN variables that id-token: write exposes:

- name: Get GitHub OIDC Workload Identity token
  id: dv-token
  run: |
    token=$(curl -sH "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
      "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://develocity.example.com" | jq -r .value)
    echo "::add-mask::$token"
    echo "key=develocity.example.com=$token" >> "$GITHUB_OUTPUT"

This step produces the same steps.dv-token.outputs.key value, so the Artifact Cache step is unchanged.

The audience passed to getIDToken (or to curl) must match the audience configured on the workload identity rule, and the hostname prefix on develocity-access-key must match the host in develocity-url (or develocity-edge-url). The token is short-lived, so mint it in every job that needs cache access rather than sharing it across jobs.

Gradle

This workflow caches Gradle dependencies through the Action.

name: Artifact Cache Gradle template

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v7

      - name: Set up Java
        uses: actions/setup-java@v5
        with:
          distribution: temurin
          java-version: 21

      - name: Develocity Artifact Cache
        uses: gradle/develocity-artifact-cache-github-action@v1
        with:
          develocity-url: https://develocity.example.com
          develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}

      - name: Build project
        run: ./gradlew build

Maven

This workflow caches Maven dependencies through the Action.

name: Artifact Cache Maven template

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v7

      - name: Set up Java
        uses: actions/setup-java@v5
        with:
          distribution: temurin
          java-version: 21

      - name: Develocity Artifact Cache
        uses: gradle/develocity-artifact-cache-github-action@v1
        with:
          develocity-url: https://develocity.example.com
          develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}

      - name: Build project
        run: ./mvnw install

npm

This workflow caches npm dependencies through the Action.

name: Artifact Cache npm template

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v7

      - name: Set up Java
        uses: actions/setup-java@v5
        with:
          distribution: temurin
          java-version: 21

      - name: Develocity Artifact Cache
        uses: gradle/develocity-artifact-cache-github-action@v1
        with:
          develocity-url: https://develocity.example.com
          develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}

      - name: Build project
        run: npm ci && npm run build

Action Inputs

Input Required Default Description

develocity-url

One of

Develocity server URL, passed to the CLI as --dv-server.

develocity-edge-url

One of

Develocity Edge URL, passed to the CLI as --dv-edge to target an Edge directly instead of a server.

develocity-access-key

Yes

Access key for the chosen endpoint host (develocity-url or develocity-edge-url) in <hostname>=<key_value> form (a bare key value is not accepted). The only key source; the DEVELOCITY_ACCESS_KEY environment variable and local key files are not read. Required to enable caching, but the Action warns and skips rather than failing the build when no key is found for the host. The Action exchanges it for a short-lived token used for its own cache restore and store and, when the CLI is downloaded from a Develocity Edge node, as the bearer credential for that download; the token is not exported to other steps.

develocity-token-expiry

No

2

Lifetime in hours of the short-lived token obtained from develocity-access-key, used for the Action’s own cache restore and store and, when the CLI is downloaded from a Develocity Edge node, as the bearer credential for that download. Raise it only if a build could run long enough for the token to expire before the post-step store.

cli-version

No

Pinned general-availability version

CLI version to download.

image-names

No

Auto-generated name (see Automatic Image Name Generation)

Ordered image names, one per line. The first is the primary; the rest are restore-only fallbacks.

additional-cli-args

No

Extra arguments appended to every restore and store call, one per line, such as --gradle-home=/home/runner/.gradle. The flags the Action controls are rejected here.

cache-read-only

No

false

When true, skip the store step.

cli-repository

No

Public Develocity download URL, or a Develocity Edge node when develocity-url addresses one running version 2.3.0 or later

CLI download source. Set to an internal mirror for air-gapped runners; an explicit value here always wins over downloading from an Edge node. Must be an HTTPS URL unless cli-repository-allow-insecure is set.

cli-repository-header

No

A single Name: Value HTTP header sent on the CLI download, for an authenticated mirror. Provide it through a secret so it is masked in logs. Ignored on the Edge node route, which authenticates with its own bearer token instead.

cli-repository-allow-insecure

No

false

Allow a cli-repository URL or a develocity-url used for the Edge node route to use plain HTTP; otherwise, an HTTP URL is rejected. Enable only for a trusted internal network without TLS: over HTTP, the download and its authentication credential (the cli-repository-header for a mirror or the short-lived bearer token for an Edge node) are sent without encryption.

cli-sha256

No

Expected CLI SHA-256, needed only to verify a version the Action does not already ship a checksum for.

Air-Gapped and Custom CLI Hosting

By default the Action downloads the CLI from the public Develocity host. To serve the CLI from your own network, set cli-repository to your mirror. For an authenticated mirror, add cli-repository-header with a Name: Value header supplied through a secret:

- name: Develocity Artifact Cache
  uses: gradle/develocity-artifact-cache-github-action@v1
  with:
    develocity-url: https://develocity.example.com
    cli-repository: https://mirror.example.com/artifact-cache-cli
    cli-repository-header: ${{ secrets.MIRROR_AUTH_HEADER }}

Automatic Image Name Generation

By default, Artifact Cache CLI generates an image name automatically when you do not set one explicitly. Automatic generation is the recommended approach: it derives the name from the build context, your project’s repository data, and the CI runner’s environment, so you do not have to choose or maintain a name yourself.

The Artifact Cache CLI inspects the following environment variables when generating image names for GitHub Runners:

  • GITHUB_WORKFLOW

  • GITHUB_REF

  • GITHUB_BASE_REF

  • GITHUB_JOB

  • GITHUB_ACTIONS

  • RUNNER_ARCH

  • RUNNER_OS

On restore the Action also tries a fallback so a branch with no cache of its own can still restore from a related branch: a pull request falls back to its base branch’s cache, and a push or manually-dispatched run falls back to the repository’s default branch, so a new branch restores instead of starting cold.

Overriding the Generated Name

Set an explicit name only when you need to control the value, for example to share one cache across differently-named jobs. With the GitHub Action, provide it through the image-names input. With the manual CLI setup, provide it with the --image-name CLI option.

Matrix Builds

The auto-generated image name isolates caches per job and by the runner’s operating system and architecture. When a build matrix adds other axes, such as a Java or tool version, those jobs share one cache unless you isolate them.

With the GitHub Action, add a dedicated image-names entry to isolate a sensitive axis.

For example, in a job with a strategy.matrix.java axis, reference that axis in image-names. A custom image-names value replaces the auto-generated name entirely, so include the runner’s operating system and architecture (which the generated name isolates on) alongside the extra axis, and use a stable prefix to namespace the project:

name: Develocity Artifact Cache
uses: gradle/develocity-artifact-cache-github-action@v1
with:
  develocity-url: https://develocity.example.com
  develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
  image-names: my-project-${{ runner.os }}-${{ runner.arch }}-java${{ matrix.java }}

Overriding the name also forgoes the automatic branch fallback described above, so prefer the generated name unless a matrix axis makes an override necessary.

Manual CLI Setup

Use the manual setup when you cannot use the GitHub Action: on air-gapped or restricted-network runners, when your organization does not permit third-party GitHub Actions, or when you need control beyond the Action’s inputs. This approach downloads the CLI and runs the restore and store commands yourself.

For an air-gapped runner that can still use the Action, point the Action at an internal mirror with cli-repository instead (see Air-Gapped and Custom CLI Hosting). Choose the manual setup when you also want to manage the restore and store steps yourself.

Storing Credentials

In your GitHub repository settings, navigate to Settings > Secrets and variables > Actions and add:

Secret Name Value

DEVELOCITY_ACCESS_KEY

Your Develocity access key: <hostname>=<key_value>

ARTIFACT_CACHE_REPO_USERNAME

Your username for your internal artifact repository

ARTIFACT_CACHE_REPO_PASSWORD

Your password for your internal artifact repository

If you use a custom internal artifact repository location, verify the "Provision and configure Artifact Cache" step. Ensure the curl command’s authentication parameters (--user) and download URL match your repository’s requirements.

Gradle Project Setup

Configuration

Add these environment variables to your workflow:

env:
  # Artifact Cache CLI Configuration
  ARTIFACT_CACHE_CLI_VERSION: 1.7.0
  ARTIFACT_CACHE_IMAGE: my-gradle-project  (1)

  # Develocity Server
  DV_SERVER: https://develocity.example.com  (2)

  # Authentication (from secrets)
  DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
  ARTIFACT_CACHE_REPO_USERNAME: ${{ secrets.ARTIFACT_CACHE_REPO_USERNAME }}
  ARTIFACT_CACHE_REPO_PASSWORD: ${{ secrets.ARTIFACT_CACHE_REPO_PASSWORD }}

  # Repository location - replace with your internal artifact repository URL
  ARTIFACT_CACHE_REPO: https://your-internal-repo.example.com/path/to/artifact-cache-cli  (3)

  # CLI Configuration
  ARTIFACT_CACHE_CLI_FILENAME: develocity-artifact-cache-cli
  ARTIFACT_CACHE_OPTS: "--gradle-home=/home/runner/.gradle"  (4)
1 Optional - leave unset for automatic generation (Recommended)
2 Replace with your Develocity server URL
3 Replace with the URL to your internal artifact repository where you’ve hosted the CLI binary
4 Assumes a Linux (Ubuntu) runner. macOS runners use /Users/runner, and Windows runners need the approach in Windows GitHub Runners. Also adjust for a custom Gradle User Home location.

Complete Workflow Example

name: Artifact Cache CLI Gradle template

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      # Artifact Cache Configuration
      ARTIFACT_CACHE_CLI_VERSION: 1.7.0
      # Develocity
      DV_SERVER: https://<develocity.address>
      DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
      # Artifact Cache CLI
      ARTIFACT_CACHE_REPO_USERNAME: ${{ secrets.ARTIFACT_CACHE_REPO_USERNAME }}
      ARTIFACT_CACHE_REPO_PASSWORD: ${{ secrets.ARTIFACT_CACHE_REPO_PASSWORD }}
      ARTIFACT_CACHE_REPO: https://your-internal-repo.example.com/path/to/artifact-cache-cli
      # Misc
      ARTIFACT_CACHE_CLI_FILENAME: develocity-artifact-cache-cli
      ARTIFACT_CACHE_OPTS: "--gradle-home=/home/runner/.gradle"
    steps:
      - name: Checkout repository
        uses: actions/checkout@v7

      - name: Setup Java (Required for Artifact Cache)
        uses: actions/setup-java@v5
        with:
          distribution: temurin
          java-version: 21

      - name: Provision and configure Artifact Cache
        shell: bash
        run: |
          TOOL_DIR="${{ runner.tool_cache }}/develocity/artifact-cache/${{ env.ARTIFACT_CACHE_CLI_VERSION }}"
          JAR_PATH="$TOOL_DIR/${{ env.ARTIFACT_CACHE_CLI_FILENAME }}.jar"
          mkdir -p "$TOOL_DIR"
          
          # Download if not present
          if [ ! -f "$JAR_PATH" ]; then
            echo "Downloading Artifact Cache CLI v${{ env.ARTIFACT_CACHE_CLI_VERSION }}..."
            curl --location --fail --silent --show-error \
              --connect-timeout 5 --max-time 30 \
              --retry 3 --retry-delay 3 --retry-max-time 60 \
              --user "$ARTIFACT_CACHE_REPO_USERNAME:$ARTIFACT_CACHE_REPO_PASSWORD" \
              "${{ env.ARTIFACT_CACHE_REPO }}/com/gradle/${{ env.ARTIFACT_CACHE_CLI_FILENAME }}/${{ env.ARTIFACT_CACHE_CLI_VERSION }}/${{ env.ARTIFACT_CACHE_CLI_FILENAME }}-${{ env.ARTIFACT_CACHE_CLI_VERSION }}.jar" \
              --output "$JAR_PATH"
          fi
          
          CMD="${{ env[format('JAVA_HOME_21_{0}', runner.arch)] }}/bin/java -jar $JAR_PATH"
          echo "ARTIFACT_CACHE_CMD=$CMD" >> $GITHUB_ENV
          
          CMD_OPTS="--dv-server=$DV_SERVER $ARTIFACT_CACHE_OPTS"
          echo "ARTIFACT_CACHE_CMD_OPTS=$CMD_OPTS" >> $GITHUB_ENV

      - name: Restore from Artifact Cache
        id: restore_cache
        run: $ARTIFACT_CACHE_CMD restore $ARTIFACT_CACHE_CMD_OPTS

      - name: Warn on Cache Restore Failure
        if: steps.restore_cache.outcome == 'failure'
        run: 'echo "WARNING: Could not restore the Artifact Cache. The build will proceed but may be slower."'

      - name: Build project
        run: ./gradlew build

      - name: Store to Artifact Cache
        if: success()
        id: store_cache
        continue-on-error: true
        run: $ARTIFACT_CACHE_CMD store $ARTIFACT_CACHE_CMD_OPTS

      - name: Warn on Cache Store Failure
        if: steps.store_cache.outcome == 'failure'
        run: 'echo "WARNING: Failed to store in the Artifact Cache."'

      - name: Persist Artifact Cache Logs
        uses: actions/upload-artifact@v4
        with:
          name: artifact-cache.log
          path: '~/.develocity/artifact-cache/artifact-cache.log'
          retention-days: 7

Key Steps Explained

Checkout Repository (First)

Always checkout before restoring cache. This ensures the repository context is available for image name generation and allows the Setup Cache to restore shared build logic content into the project directory.

Setup Java

The Artifact Cache CLI requires Java 21. Use actions/setup-java with java-version: 21.

Provision and Configure

Downloads the Artifact Cache CLI JAR if not already cached in the runner’s tool cache. Sets up environment variables for subsequent steps.

Restore from Artifact Cache

Runs before the build to restore cached dependencies. Uses continue-on-error behavior via conditional warning.

Store to Artifact Cache

Runs after successful build to update the cache. Uses if: success() and continue-on-error: true to not fail the build if store fails.

Persist Logs

Uploads diagnostic logs for troubleshooting. Recommended for all workflows.

Shared Build Logic Caching

Starting with Artifact Cache CLI version 1.1.0, the Setup Cache automatically caches shared Gradle build logic defined in buildSrc and included builds. This feature requires the Develocity Gradle Plugin version 4.4.1 or later, and has the following constraints:

  • The absolute project checkout path must remain constant across builds. GitHub Actions uses a stable path by default (/home/runner/work/<repository>/<repository>).

  • The repository checkout must happen before the restore command.

Maven Project Setup

Configuration

env:
  # Change only these for Maven
  ARTIFACT_CACHE_IMAGE: my-maven-project (1)
  ARTIFACT_CACHE_OPTS: "--maven-home=/home/runner/.m2"  (2)
1 Optional - leave unset for automatic generation (Recommended)
2 Assumes a Linux (Ubuntu) runner. macOS runners use /Users/runner, and Windows runners need the approach in Windows GitHub Runners. For a custom Maven repository, add --maven-repository=/custom/path.

Complete Workflow Example

name: Artifact Cache CLI Maven template

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      # Artifact Cache Configuration
      ARTIFACT_CACHE_CLI_VERSION: 1.7.0
      # Develocity
      DV_SERVER: https://<develocity.address>
      DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
      # Artifact Cache CLI
      ARTIFACT_CACHE_REPO_USERNAME: ${{ secrets.ARTIFACT_CACHE_REPO_USERNAME }}
      ARTIFACT_CACHE_REPO_PASSWORD: ${{ secrets.ARTIFACT_CACHE_REPO_PASSWORD }}
      ARTIFACT_CACHE_REPO: https://your-internal-repo.example.com/path/to/artifact-cache-cli
      # Misc
      ARTIFACT_CACHE_CLI_FILENAME: develocity-artifact-cache-cli
      ARTIFACT_CACHE_OPTS: "--maven-home=/home/runner/.m2"
    steps:
      - name: Checkout repository
        uses: actions/checkout@v7

      - name: Setup Java (Required for Artifact Cache)
        uses: actions/setup-java@v5
        with:
          distribution: temurin
          java-version: 21

      - name: Provision and configure Artifact Cache
        shell: bash
        run: |
          TOOL_DIR="${{ runner.tool_cache }}/develocity/artifact-cache/${{ env.ARTIFACT_CACHE_CLI_VERSION }}"
          JAR_PATH="$TOOL_DIR/${{ env.ARTIFACT_CACHE_CLI_FILENAME }}.jar"
          mkdir -p "$TOOL_DIR"
          
          # Download if not present
          if [ ! -f "$JAR_PATH" ]; then
            echo "Downloading Artifact Cache CLI v${{ env.ARTIFACT_CACHE_CLI_VERSION }}..."
            curl --location --fail --silent --show-error \
              --connect-timeout 5 --max-time 30 \
              --retry 3 --retry-delay 3 --retry-max-time 60 \
              --user "$ARTIFACT_CACHE_REPO_USERNAME:$ARTIFACT_CACHE_REPO_PASSWORD" \
              "${{ env.ARTIFACT_CACHE_REPO }}/com/gradle/${{ env.ARTIFACT_CACHE_CLI_FILENAME }}/${{ env.ARTIFACT_CACHE_CLI_VERSION }}/${{ env.ARTIFACT_CACHE_CLI_FILENAME }}-${{ env.ARTIFACT_CACHE_CLI_VERSION }}.jar" \
              --output "$JAR_PATH"
          fi
          
          CMD="${{ env[format('JAVA_HOME_21_{0}', runner.arch)] }}/bin/java -jar $JAR_PATH"
          echo "ARTIFACT_CACHE_CMD=$CMD" >> $GITHUB_ENV
          
          CMD_OPTS="--dv-server=$DV_SERVER $ARTIFACT_CACHE_OPTS"
          echo "ARTIFACT_CACHE_CMD_OPTS=$CMD_OPTS" >> $GITHUB_ENV

      - name: Restore from Artifact Cache
        id: restore_cache
        run: $ARTIFACT_CACHE_CMD restore $ARTIFACT_CACHE_CMD_OPTS

      - name: Warn on Cache Restore Failure
        if: steps.restore_cache.outcome == 'failure'
        run: 'echo "WARNING: Could not restore the Artifact Cache. The build will proceed but may be slower."'

      - name: Build project
        run: ./mvnw install

      - name: Store to Artifact Cache
        if: success()
        id: store_cache
        continue-on-error: true
        run: $ARTIFACT_CACHE_CMD store $ARTIFACT_CACHE_CMD_OPTS

      - name: Warn on Cache Store Failure
        if: steps.store_cache.outcome == 'failure'
        run: 'echo "WARNING: Failed to store in the Artifact Cache."'

      - name: Persist Artifact Cache Logs
        uses: actions/upload-artifact@v4
        with:
          name: artifact-cache.log
          path: '~/.develocity/artifact-cache/artifact-cache.log'
          retention-days: 7

Custom Maven Repository Path

If your project uses a custom Maven repository location (via -Dmaven.repo.local or settings.xml), add the --maven-repository option:

env:
  ARTIFACT_CACHE_OPTS: "--maven-home=/home/runner/.m2 --maven-repository=/custom/repo"

npm Project Setup

Configuration

env:
  # Change only these for npm
  ARTIFACT_CACHE_IMAGE: my-npm-project (1)
  ARTIFACT_CACHE_OPTS: "--npm-home=/home/runner/.npm"  (2)
1 Optional - leave unset for automatic generation (Recommended)
2 Assumes a Linux (Ubuntu) runner. macOS runners use /Users/runner, and Windows runners need the approach in Windows GitHub Runners.

Complete Workflow Example

name: Artifact Cache CLI npm template

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      # Artifact Cache Configuration
      ARTIFACT_CACHE_CLI_VERSION: 1.7.0
      # Develocity
      DV_SERVER: https://<develocity.address>
      DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
      # Artifact Cache CLI
      ARTIFACT_CACHE_REPO_USERNAME: ${{ secrets.ARTIFACT_CACHE_REPO_USERNAME }}
      ARTIFACT_CACHE_REPO_PASSWORD: ${{ secrets.ARTIFACT_CACHE_REPO_PASSWORD }}
      ARTIFACT_CACHE_REPO: https://your-internal-repo.example.com/path/to/artifact-cache-cli
      # Misc
      ARTIFACT_CACHE_CLI_FILENAME: develocity-artifact-cache-cli
      ARTIFACT_CACHE_OPTS: "--npm-home=/home/runner/.npm"
    steps:
      - name: Checkout repository
        uses: actions/checkout@v7

      - name: Setup Java (Required for Artifact Cache)
        uses: actions/setup-java@v5
        with:
          distribution: temurin
          java-version: 21

      - name: Provision and configure Artifact Cache
        shell: bash
        run: |
          TOOL_DIR="${{ runner.tool_cache }}/develocity/artifact-cache/${{ env.ARTIFACT_CACHE_CLI_VERSION }}"
          JAR_PATH="$TOOL_DIR/${{ env.ARTIFACT_CACHE_CLI_FILENAME }}.jar"
          mkdir -p "$TOOL_DIR"
          
          # Download if not present
          if [ ! -f "$JAR_PATH" ]; then
            echo "Downloading Artifact Cache CLI v${{ env.ARTIFACT_CACHE_CLI_VERSION }}..."
            curl --location --fail --silent --show-error \
              --connect-timeout 5 --max-time 30 \
              --retry 3 --retry-delay 3 --retry-max-time 60 \
              --user "$ARTIFACT_CACHE_REPO_USERNAME:$ARTIFACT_CACHE_REPO_PASSWORD" \
              "${{ env.ARTIFACT_CACHE_REPO }}/com/gradle/${{ env.ARTIFACT_CACHE_CLI_FILENAME }}/${{ env.ARTIFACT_CACHE_CLI_VERSION }}/${{ env.ARTIFACT_CACHE_CLI_FILENAME }}-${{ env.ARTIFACT_CACHE_CLI_VERSION }}.jar" \
              --output "$JAR_PATH"
          fi
          
          CMD="${{ env[format('JAVA_HOME_21_{0}', runner.arch)] }}/bin/java -jar $JAR_PATH"
          echo "ARTIFACT_CACHE_CMD=$CMD" >> $GITHUB_ENV
          
          CMD_OPTS="--dv-server=$DV_SERVER $ARTIFACT_CACHE_OPTS"
          echo "ARTIFACT_CACHE_CMD_OPTS=$CMD_OPTS" >> $GITHUB_ENV

      - name: Restore from Artifact Cache
        id: restore_cache
        run: $ARTIFACT_CACHE_CMD restore $ARTIFACT_CACHE_CMD_OPTS

      - name: Warn on Cache Restore Failure
        if: steps.restore_cache.outcome == 'failure'
        run: 'echo "WARNING: Could not restore the Artifact Cache. The build will proceed but may be slower."'

      - name: Build project
        run: npm ci && npm run build

      - name: Store to Artifact Cache
        if: success()
        id: store_cache
        continue-on-error: true
        run: $ARTIFACT_CACHE_CMD store $ARTIFACT_CACHE_CMD_OPTS

      - name: Warn on Cache Store Failure
        if: steps.store_cache.outcome == 'failure'
        run: 'echo "WARNING: Failed to store in the Artifact Cache."'

      - name: Persist Artifact Cache Logs
        uses: actions/upload-artifact@v4
        with:
          name: artifact-cache.log
          path: '~/.develocity/artifact-cache/artifact-cache.log'
          retention-days: 7

SonarScanner Caching

SonarScanner caching layers on top of your existing project setup. The Artifact Cache CLI auto-detects the SonarScanner user home from $SONAR_USER_HOME, falling back to ~/.sonar. No extra configuration is required as long as the directory exists when restore or store runs.

If your workflow caches ~/.sonar or ~/.sonar/cache via actions/cache, remove that step. The Artifact Cache CLI handles SonarScanner caching automatically.

Expect image growth of roughly 50 to 100 MB per analyzer version stored.

If the directory is created during build execution, pin it explicitly by appending --sonar-home to the CLI arguments. With the GitHub Action, add it to additional-cli-args; with the manual setup, add it to ARTIFACT_CACHE_OPTS:

env:
  ARTIFACT_CACHE_OPTS: "--gradle-home=/home/runner/.gradle --sonar-home=/home/runner/.sonar"

To opt out of SonarScanner caching even when the user home is present, exclude it from auto-detection:

env:
  ARTIFACT_CACHE_OPTS: "--gradle-home=/home/runner/.gradle --no-autodetect=SONAR"

Windows GitHub Runners

Windows runners require additional configuration due to path handling differences.

- name: Set Dynamic Environment Variables
  shell: bash
  run: |
    NORMALIZED_TOOL_PATH=$(echo "${{ runner.tool_cache }}" | sed 's|\\|/|g' | sed 's|^C:/|/c/|i')
    echo "DV_ARTIFACT_CACHE_JAR_PATH=$NORMALIZED_TOOL_PATH/develocity/${{ env.DV_ARTIFACT_CACHE_CLI_VERSION }}/develocity-artifact-cache-cli.jar" >> $GITHUB_ENV
    echo "DV_CACHE_DIR=$HOME/.gradle" >> $GITHUB_ENV
    NORMALIZED_JAVA_PATH=$(echo "${{ env[format('JAVA_HOME_21_{0}', runner.arch)] }}" | sed 's|\\|/|g' | sed 's|^C:/|/c/|i')
    echo "DV_JAVA=$NORMALIZED_JAVA_PATH/bin/java" >> $GITHUB_ENV
#...
- name: Restore Artifact Cache
  id: restore_cache
  shell: bash
  run: |
    $DV_JAVA -jar "${{ env.DV_ARTIFACT_CACHE_JAR_PATH }}" \
    restore \
    --server="${{ env.DV_SERVER }}" \
    --image-name="${{ env.DV_ARTIFACT_CACHE_IMAGE }}" \
    --gradle-home="${{ env.DV_CACHE_DIR }}"