skip to content

How do you author your own BOM/platform in Gradle, and what does the constraints block do?

level: middleimportance: should knowfreq 50%

answer

  1. java-platform plugin
  2. constraints { api / runtime }
  3. no jar, BOM only
  4. from(components[javaPlatform])
  5. allowDependencies() to opt in

basics

~10 s

Apply the java-platform plugin in a dedicated project and declare versions in a dependencies { constraints { api(...) / runtime(...) } } block. Published, it becomes a BOM others import with platform().

solid answer

~40 s

You create a dedicated project, apply the **`java-platform`** plugin, and declare versions inside `dependencies { constraints { … } }`. The platform produces no jar — only a BOM (a POM with `<dependencyManagement>`) when published with `maven-publish`. Inside `constraints` you use two scopes: **`api`** for constraints that should be visible to consumers of the platform (the common case), and **`runtime`** for constraints that apply only at runtime. By default a `java-platform` can only declare constraints, not depend on real components; to also align versions of a project's own dependencies you can opt in with `javaPlatform { allowDependencies() }`. Consumers then write `implementation(platform("my.group:my-platform:1.0"))` and omit versions. This is how an org centralizes a single, versioned source of truth that many repos import.

code

kotlin · 19 lines
kotlin
plugins {
    `java-platform`
    `maven-publish`
}

dependencies {
    constraints {
        api("com.fasterxml.jackson.core:jackson-databind:2.17.0")
        runtime("org.postgresql:postgresql:42.7.3")
    }
}

publishing {
    publications {
        create<MavenPublication>("platform") {
            from(components["javaPlatform"])
        }
    }
}

go deeper

for a junior

Recognize that java-platform lets you publish a BOM via a constraints block.

for a middle

Know the plugin, the api/runtime constraint scopes, that it publishes only a POM, and how to wire maven-publish.

for a senior

Explain allowDependencies(), api-vs-runtime visibility implications, and consuming the platform via platform().

for a principal

Position an org platform project as version governance; manage its release cadence and the blast radius of bumps across repos.

## Goal Instead of *importing* someone else's BOM, you can **author** one so every project in your org aligns on the same versions. Gradle does this with the `java-platform` plugin. ## Setup Create a standalone project (e.g. `platform/`) and apply the plugin: ```kotlin plugins { `java-platform` `maven-publish` } dependencies { constraints { api("com.fasterxml.jackson.core:jackson-databind:2.17.0") api("org.apache.commons:commons-lang3:3.14.0") runtime("org.postgresql:postgresql:42.7.3") } } publishing { publications { create<MavenPublication>("platform") { from(components["javaPlatform"]) } } } ``` ## The constraints block `constraints { }` declares version recommendations **without** introducing dependencies. The configuration you attach each constraint to controls visibility: - **`api(...)`** — the constraint is part of the platform's public API and is exposed to consumers. Use this for versions you want everyone importing the platform to inherit. This is the usual choice. - **`runtime(...)`** — the constraint applies to the runtime classpath only (not compile). Use for things only needed at runtime, like a JDBC driver. ## No jar, only metadata A `java-platform` component contributes **no artifact**. Publishing it yields a POM whose `<dependencyManagement>` mirrors your constraints — i.e. a real BOM consumable by both Gradle (`platform(...)`) and Maven (`import` scope). ## Declaring real dependencies By default a platform may **only** declare constraints; trying to declare a normal dependency fails. If you want the platform to also align its own transitive dependencies, opt in: ```kotlin javaPlatform { allowDependencies() } ``` This is useful when your platform itself imports other platforms. ## Consuming it ```kotlin dependencies { implementation(platform("com.acme:acme-platform:1.0")) implementation("com.fasterxml.jackson.core:jackson-databind") // version from the platform } ``` ## Why author one - Single, versioned source of truth across many repos. - Bumping the platform version upgrades a whole fleet. - Plays the same role as Spring Boot's BOM but for your own stack.

  • What is the difference between declaring a constraint with api(...) versus runtime(...) in a java-platform?
    api(...) exposes the constraint to consumers of the platform (visible on their compile and runtime graphs), so it is the usual choice; runtime(...) limits the constraint to the runtime classpath, suitable for things like JDBC drivers that aren't needed at compile time.
  • Can a java-platform project declare normal dependencies, and how do you enable that?
    By default no — it may only declare constraints, and a normal dependency throws an error. Call javaPlatform { allowDependencies() } to permit real dependencies, e.g. when importing another platform.
  • Does the published java-platform include a jar?
    No. It publishes only a POM with a <dependencyManagement> section — a BOM. There is no artifact to download.

saying these in an interview costs you the question

  • Using the java-library or java plugin to publish a BOM — you need java-platform.
  • Expecting a jar artifact from a platform.
  • Declaring real dependencies in a java-platform without calling allowDependencies().

context