This page is a reference for integrating Gradle with GitLab CI/CD on GitLab.com, self-managed, or GitLab Dedicated instances.

Using the GitLab-provided template

GitLab ships an official Gradle CI template at Gradle.gitlab-ci.yml. Include it with:

include:
  - template: Gradle.gitlab-ci.yml

The template defines three stages, build, test, deploy, using the gradle:alpine image, and configures a .gradle/ cache keyed by branch. Use it as a starting point; most projects override the image and script sections to pin a specific JDK and use the Gradle Wrapper.

Minimal pipeline

A reference .gitlab-ci.yml that builds a Gradle project using the Wrapper and publishes test results:

image: eclipse-temurin:21

variables:
  GRADLE_USER_HOME: "$CI_PROJECT_DIR/.gradle"
  GRADLE_OPTS: "-Dorg.gradle.daemon=false"

build:
  stage: build
  script:
    - ./gradlew --no-daemon build
  artifacts:
    when: always
    reports:
      junit: "**/build/test-results/test/TEST-*.xml"
    paths:
      - "**/build/reports"
    expire_in: 1 week
  • image provides the JDK; the Gradle Wrapper supplies Gradle itself.

  • GRADLE_USER_HOME is placed inside $CI_PROJECT_DIR so it falls within GitLab’s cacheable and uploadable area.

  • GRADLE_OPTS=-Dorg.gradle.daemon=false disables the Gradle daemon on short-lived runners.

  • reports:junit surfaces test results directly on the merge request and pipeline pages.

Caching

GitLab caches are scoped by key and stored per runner (for project runners) or on shared object storage (for SaaS shared runners). Two patterns are common.

Wrapper-only cache

Recommended for SaaS shared runners, where uploading a large cache archive often outweighs the savings:

variables:
  GRADLE_USER_HOME: "$CI_PROJECT_DIR/.gradle"

cache:
  key:
    files:
      - gradle/wrapper/gradle-wrapper.properties
  paths:
    - .gradle/wrapper

Keying on gradle-wrapper.properties means the cache is rebuilt only when the Gradle version changes.

Full Gradle User Home cache

Appropriate for dedicated or self-hosted runners with local cache storage:

variables:
  GRADLE_USER_HOME: "$CI_PROJECT_DIR/.gradle"

cache:
  key: "$CI_COMMIT_REF_SLUG"
  paths:
    - .gradle/caches
    - .gradle/wrapper
    - .gradle/notifications

For cross-branch dependency reuse, prefer a Gradle Remote Build Cache.

Cache policies across stages

For multi-stage pipelines, use the push / pull / pull-push (default) policy to control which jobs write the cache:

build:
  stage: build
  cache:
    key: "$CI_COMMIT_REF_SLUG"
    policy: pull-push
    paths: [.gradle]

test:
  stage: test
  cache:
    key: "$CI_COMMIT_REF_SLUG"
    policy: pull
    paths: [.gradle]

The build job populates the cache; downstream jobs read from it without uploading.

Publishing Build Scans

To publish Gradle Build Scans® from GitLab CI, apply the Develocity plugin in settings.gradle[.kts] and accept the terms of use when running under CI:

plugins {
    id("com.gradle.develocity") version "3.18.1"
}

develocity {
    buildScan {
        if (System.getenv("CI") != null) {
            termsOfUseUrl = "https://gradle.com/help/legal-terms-of-use"
            termsOfUseAgree = "yes"
            publishing.onlyIf { true }
        }
    }
}

GitLab CI sets CI=true automatically. Build Scan URLs are printed to the job log and can be linked from merge request discussions.

Merge request and branch pipelines

Use rules to distinguish merge-request pipelines from branch pipelines — for example, to skip slow integration tests on feature branches:

integration-test:
  stage: test
  script: ./gradlew integrationTest
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'

Release pipelines

A typical Gradle release pipeline on GitLab CI combines a versioning plugin (such as Axion Release) with publish targeting GitLab’s Maven Package Registry or an external repository. The pattern described in Release Gradle project using GitLab CI/CD pipeline is:

variables:
  # Required so Axion Release can read existing version tags
  GIT_FETCH_EXTRA_FLAGS: --tags

release:
  stage: release
  script:
    - ./gradlew createRelease -Prelease.customUsername=$GITLAB_USER -Prelease.customPassword=$GITLAB_TOKEN
    - ./gradlew publish
    - echo "VERSION=$(./gradlew -q currentVersion)" >> variables.env
  artifacts:
    reports:
      dotenv: variables.env
  rules:
    # Skip when the pipeline is triggered by a tag the release job itself pushed
    - if: $CI_COMMIT_TAG
      when: never
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Key points:

  • GIT_FETCH_EXTRA_FLAGS: --tags exposes existing version tags to the job; without it, Axion (and similar plugins) cannot compute the next version.

  • The release job needs write access to push the new tag back — supply a project access token or deploy key with write_repository scope via GITLAB_TOKEN.

  • The rules block prevents the tag push from triggering a recursive release.

  • Credentials for publishing (for example CI_REPOSITORY_USERNAME / CI_REPOSITORY_PASSWORD) are set as masked/protected CI/CD variables in the project settings, then read by build.gradle[.kts]:

    publishing {
        repositories {
            maven {
                url = uri("${System.getenv("CI_API_V4_URL")}/projects/${System.getenv("CI_PROJECT_ID")}/packages/maven")
                credentials(HttpHeaderCredentials::class) {
                    name = "Job-Token"
                    value = System.getenv("CI_JOB_TOKEN")
                }
                authentication {
                    create<HttpHeaderAuthentication>("header")
                }
            }
        }
    }

A downstream GitLab release job can then consume the VERSION dotenv artifact to create a GitLab Release entry.

Useful predefined variables

Variable Purpose

CI

Always true in GitLab CI. Use to branch Gradle build logic.

CI_PROJECT_DIR

Absolute path to the checked-out repository. Base for GRADLE_USER_HOME.

CI_COMMIT_REF_SLUG

URL-safe branch/tag name. Common cache:key.

CI_COMMIT_BRANCH / CI_COMMIT_TAG

Populated on branch and tag pipelines respectively. Use in rules.

CI_PIPELINE_SOURCE

Trigger type (push, merge_request_event, schedule, web, …).

CI_JOB_TOKEN

Short-lived token for authenticating to the project’s package registry and API.

CI_API_V4_URL / CI_PROJECT_ID

Compose URLs to the GitLab API and package registries.

See Predefined CI/CD variables for the full list.