Chapter 20Lesson 03~185 minutes

Version Catalogs, Platforms, Constraints, Dependency Locking, and Centralized Version Governance: Configuration, Design Choices, and Tradeoffs

Choose deliberately between catalogs, platforms, rich constraints, enforced platforms, and locking by matching each mechanism to the build state it actually controls.

GovernanceRich versionsenforcedPlatformLock scopeInteroperability

Learning objectives

  • Choose between a catalog alias and a platform constraint by whether the requirement concerns declaration ergonomics or graph policy.
  • Use strict or enforced controls only when their downstream compatibility cost is justified by evidence.
  • Decide whether to lock all resolvable configurations or only a bounded production-relevant set.
  • Compare one centralized catalog with independently versioned/published platform modules for multi-repository organizations.
  • Explain the interoperability consequences of rich Gradle constraints and Maven consumers.
  • Design review boundaries that keep platform changes and lock-state changes auditable.

1. Governance design is about choosing the narrowest truthful mechanism

After Lesson 2, it is tempting to put every version in every mechanism “for safety.” That creates duplicate sources of truth and confusing failure messages. A better design asks what decision is being made: alias spelling, allowed versions, exact currently resolved versions, or downstream publication policy.

2. Decision table: match the mechanism to the problem

Problem Primary mechanism Why Evidence
Reduce duplicated coordinates in build scripts Version catalog Improves declaration ergonomics/type-safe accessors without pretending to be graph enforcement. TOML diff + build declarations.
Align a family of modules across several subprojects Regular platform + constraints Constraints participate in transitive graph resolution and can be shared/published. Platform diff + dependencyInsight.
Forbid a known-incompatible version range Rich constraint with strictly/reject Expresses compatibility policy directly in the graph. Constraint reason + failed/successful resolution.
Reproduce the selected module versions tomorrow Dependency locking Captures resolved versions for locked configurations. Reviewed gradle.lockfile diff.
Force an application stack to one platform regardless of graph requests Possibly enforcedPlatform Strong transitive override; appropriate only when that coupling is intentional. Insight shows Forced/constraint reasons; downstream impact test.
Verify downloaded bytes/provenance Dependency verification, not this chapter’s mechanisms Versions do not prove integrity. Chapter 28 verification metadata/checksums/signatures.

3. Catalog alias versus platform constraint

A catalog is local build authoring infrastructure. Downstream consumers of a published library cannot tell whether its dependency was spelled with libs.foo. A platform is a dependency component in the graph; its constraints can be consumed and published. Therefore a team-wide compatibility promise belongs in a platform more naturally than in a repository-local alias file.

Catalog versions can still be useful—for plugins, test-only tooling, or a small build that does not need a platform. The anti-pattern is assuming “central” means “enforced.”

4. Flexible constraints versus strict/enforced control

Gradle’s default required-version semantics are intentionally optimistic: conflict resolution can select a higher version. prefer is softer still. strictly excludes values outside the accepted expression and can cause resolution failure. enforcedPlatform goes further by forcing platform versions and exporting that force transitively.

Control Strength Good fit Cost/risk
Required version Compatible higher selections can win Normal application/library dependency requirements May allow an untested higher conflict winner.
Preferred version Soft Known-good default inside flexible ecosystem policy Easily overridden by stronger opinions.
Strict constraint Hard compatibility boundary Known incompatible ranges, tested platform baseline Can make graphs fail and constrain downstream consumers.
Enforced platform Force-like and transitive Tightly controlled application stack Can surprise/restrict library consumers; use cautiously.

For reusable components, publishing accurate constraints is generally more cooperative than exporting force-like behavior. If strictness is necessary, include a because(...) rationale and test downstream integration.

5. Lock all configurations versus selected configurations

lockAllConfigurations() is simple and often suitable for JVM applications, but a large build can have tooling, platform-specific, or environment-specific resolvable configurations that should not all be locked from one machine. Gradle supports activating locking on individual configurations, and its documentation shows custom “resolve and lock all” tasks when teams need controlled coverage.

Choose lock scope based on what must be reproducible in CI. The review question is not “did we create a lockfile?” but “which production-relevant resolvable configurations were covered, and which intentionally were not?”

6. One catalog versus independently versioned platforms

Architecture Benefits Tradeoffs Use when
Single repository catalog Low ceremony; convenient aliases; one review surface Repository-local; not a published compatibility contract Monorepo/single product where teams share one source tree.
Published version catalog Share aliases across repositories Still declaration intent, not graph enforcement; catalog artifact lifecycle required Organizations that want consistent notation across independent builds.
Published Java platform/BOM Graph-level constraints shared across builds; Maven BOM interoperability for basic constraint model Requires release/version lifecycle; rich Gradle semantics can be lossy in Maven metadata Compatibility policy must travel with consumers.
Bounded domain platforms Smaller blast radius and independent release cadence More platform dependencies/version coordination Large organizations with distinct stacks/domains.

7. Gradle-rich policy versus Maven interoperability

Java platforms can publish both Gradle Module Metadata and Maven BOM-style metadata, but not every rich Gradle semantic maps losslessly to Maven. Gradle documents that rich-version information may be reduced when converted to Maven/Ivy metadata, and rejects are not preserved in the same way. If Maven consumers are a first-class requirement, test the published POM/BOM as a Maven consumer would see it rather than assuming Gradle’s graph semantics travel intact.

8. Lock state is a review artifact, not an automatic upgrade mechanism

A broad --write-locks can legitimately rewrite many entries if the graph changed. That is exactly why dependency updates should be reviewable. For a single planned upgrade, prefer --update-locks group:module, inspect the graph, and explain every additional diff. Automation should open a change with evidence; it should not silently regenerate lockfiles on every CI build.

9. Worked scenario: choose a policy for an internal platform

A company has eight Gradle services and two Maven services. All must use a tested Commons Lang baseline, but each repository has independent test-tool versions.

  1. Publish a small Java platform/BOM for runtime compatibility policy so both Gradle and Maven services can consume the basic version constraints.
  2. Keep each Gradle repository’s test-tool aliases in its local catalog unless organization-wide sharing has a real benefit.
  3. Use ordinary/strict constraints only where compatibility evidence justifies them; avoid enforcedPlatform in a reusable library.
  4. Commit lock state per Gradle service to capture its resolved graph, and update locks only during reviewed dependency changes.
  5. Test the generated Maven BOM separately because rich Gradle metadata may not map 1:1.

10. Boundary checklist

  • Gradle/JDK: wrapper/runtime version is separate from dependency version policy.
  • Repository manager: decides where artifacts may resolve from; a platform does not define repository trust.
  • CI: decides when lock updates are allowed; ordinary verification builds should not mutate lock state.
  • IDE: may suggest upgrades but must not be treated as the authoritative graph decision.
  • OS/cache: warm dependency cache affects timing, not accepted version policy.

Knowledge check

When should a team prefer a platform over a catalog version?

Why can enforcedPlatform be inappropriate for a reusable library?

What question determines whether to lock all configurations?

Can a Maven consumer reproduce every rich Gradle constraint from Gradle Module Metadata?

Should CI regenerate lockfiles on every normal build?

A platform constraint and lockfile both say 3.20.0. Which is the policy and which is captured state?

Official references and version notes

Version-sensitive statements were rechecked for Gradle 9.7.1 on 2026-08-24. This chapter does not depend on Maven 4, a third-party Gradle plugin, hosted CI, or a commercial repository.

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.