Chapter 26Lesson 03~235 minutes

Gradle Publishing, Maven Publish, Ivy Publish, Signing, Metadata, and Repository Promotion: Configuration, Design Choices, and Tradeoffs

Choose Maven or Ivy metadata, rich Gradle metadata, signing, repository topology, and staging/promotion controls by tracing the consumer contract, trust boundary, reproducibility requirement, and operational ownership each choice changes.

InteroperabilityPromotionMetadata policyCredentialsImmutability

Learning objectives

  • Choose Maven or Ivy publishing formats according to consumer ecosystems rather than personal DSL preference.
  • Decide when rich Gradle metadata is safe, when Maven compatibility constrains the model, and how version mapping changes POM evidence.
  • Separate direct publication from repository-managed staging/promotion.
  • Choose credential/signing placement and local-versus-authoritative repository policy.
  • Justify each choice using observable repository and consumer behavior.

1. Maven versus Ivy is a consumer-contract decision

Do not start with “which Gradle plugin do I like?” Start with the consumers and repository manager. Maven-format repositories are the broad JVM interoperability default. Ivy remains useful where an organization deliberately operates Ivy metadata/layouts or needs Ivy-specific descriptor semantics. Applying both in one build can be useful for learning, but publishing two authoritative formats for the same product creates more metadata to govern.

2. Rich GMM versus Maven-compatible surface

Gradle consumers can use GMM to select variants with attributes/capabilities that a Maven POM cannot model. Maven consumers see the POM only. A library that exposes a plain Java API/runtime split usually maps cleanly. A library with custom variants, rich constraints, or Gradle-specific capabilities may not.

Publication warnings are therefore design feedback. Before suppressing one, compare the resolved graph from a clean Gradle consumer and a clean Maven consumer. If the graphs or available artifacts differ in a way that changes runtime behavior, the problem is not cosmetic.

3. Declared versus resolved dependency versions in POMs

By default, Maven Publish writes the versions declared by the build model. Gradle also supports versionMapping to publish resolved versions. That can be appropriate when a release is tested against locked/resolved versions or when rich Gradle constraints would map poorly to Maven.

publishing {
    publications {
        named<MavenPublication>("mavenJava") {
            versionMapping {
                usage("java-api") {
                    fromResolutionOf("runtimeClasspath")
                }
                usage("java-runtime") {
                    fromResolutionResult()
                }
            }
        }
    }
}

This is not universally “more reproducible.” It changes the public dependency contract. Review the generated POM diff and consumer graph before adopting it, especially for libraries whose API dependencies intentionally allow a range of compatible versions.

4. Direct-to-release versus stage-then-promote

Direct publication minimizes moving parts but gives the build job immediate authority over the release repository. Staging adds a state boundary: upload candidate bytes once, run verification against those exact bytes, then promote them without rebuilding. For commercial/internal repositories, that separation usually makes audit and rollback reasoning clearer.

Model Advantage Risk / cost Evidence to require
Direct publish Simple and fast Publish job can create/replace authoritative identity immediately Exact coordinate, permission check, repository immutability, checksum/signature evidence
Staging + promotion Verify exact candidate before release visibility Needs repository-manager workflow and retention policy Staging digest = promoted digest; approval/audit record
Build again during release Operationally familiar in some pipelines Second build may produce different bytes/metadata Avoid as promotion strategy; if unavoidable, treat as a new artifact and re-verify

5. Maven Local versus disposable file repo versus authoritative remote

Maven Local is a user cache and diagnostic bridge. A project-relative file repository is better for this course because its complete layout can be inspected, copied, hashed, and deleted as one lab artifact. Neither is a production release service. An authoritative repository adds access control, immutable releases, retention, replication, audit, and promotion semantics that Gradle alone does not provide.

6. Credentials and signing are separate authorization layers

Repository credentials answer “may this build write here?” A signing key answers “which cryptographic identity produced this signature?” The same CI job may possess both, but that does not make them the same secret. Least privilege often means a snapshot job can upload snapshots without a release signing key, while a protected release job receives both narrowly scoped repository write permission and signing capability.

Use repository-name-derived Gradle properties or provider-backed environment inputs. Never echo them. A Configuration Cache can serialize values used during configuration, so secret-handling policy must also consider cache storage and access controls.

7. Snapshots, releases, and mutable identity

A -SNAPSHOT version communicates changing development state in Maven conventions. A non-snapshot release should be immutable. Gradle can route repositories conditionally based on the project version, but routing is not an immutability guarantee; the destination repository must enforce the rule.

publishing {
    repositories {
        maven {
            name = "target"
            val releasesRepo = layout.buildDirectory.dir("repositories/releases")
            val snapshotsRepo = layout.buildDirectory.dir("repositories/snapshots")
            url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepo else releasesRepo)
        }
    }
}

This snippet is safe only as a routing example. Production URLs, credentials, retention, and overwrite policy belong to repository governance.

8. Decision table

Situation Recommended publishing approach Why
Public/general JVM library Maven publication + GMM; validate Maven consumer Broad interoperability while preserving richer Gradle metadata
Internal Gradle-only ecosystem with custom variants Maven or Ivy repository + GMM, with explicit compatibility boundary Gradle consumers can use rich variants; non-Gradle limitations are documented
Legacy Ivy estate Ivy publication, optionally GMM for Gradle consumers Matches existing repository/consumer metadata model
Release requiring approval/security gates Publish candidate once to staging, then repository-managed promotion Build once; verify/promote identical bytes
Local integration experiment Disposable project-relative Maven repository Inspectable and deletable; avoids normal Maven Local state
Developer convenience only Optional Maven Local diagnostic Useful bridge, but too mutable for authoritative release identity

9. Worked scenario: one Gradle service team, two consumer ecosystems

A platform team owns a Java library consumed by 40 Gradle builds and 12 Maven builds. The Gradle consumers benefit from rich variants, but the Maven consumers must still receive a correct dependency graph. The team chooses Maven repository layout, publishes GMM alongside the POM, runs a Gradle consumer verification and Maven consumer verification against staging, signs the staged publication, and promotes the same coordinate tree. It does not create a Gradle-only release repository plus a separately rebuilt Maven artifact.

10. What this chapter does not configure

Gradle build logic can define publications, tasks, repository URLs, and credential interfaces. It does not administer Nexus/Artifactory retention, Maven Central namespaces, CI protected environments, organizational key custody, legal release approval, or vulnerability policy. Those systems consume the publication contract defined here.

Knowledge check

When is versionMapping a meaningful design change rather than formatting?

Why not publish separately rebuilt Gradle and Maven “release artifacts”?

Does routing -SNAPSHOT and release versions to different URLs enforce immutability?

What is the strongest reason to keep Maven consumer verification even when most consumers use Gradle?

Should a snapshot uploader automatically have access to the production signing key?

Official references and version notes

Version-sensitive behavior was rechecked against current Gradle and Apache Maven primary documentation on 2026-08-24. Mandatory publication uses only repository-owned files plus disposable file: repositories under the lab workspace. Maven Local, real credentials, real release repositories, hosted signing, Maven Central, Nexus/Artifactory administration, and CI-specific secret stores are not mandatory.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.