How does io.spring.dependency-management relate to the Spring Boot plugin, and how does BOM-aligned version management work in a Gradle build?
answer
- BOM = spring-boot-dependencies
- platform() native import vs dependency-management plugin
- constraints, not dependencies
- versionless starters
- override via ext[...version] or constraints
basics
~10 sThe Spring Boot plugin imports the Boot BOM so you can declare dependencies without versions, and Gradle resolves consistent, tested versions for you. Versionless starters 'just work' because the BOM pins them.
solid answer
~40 sSpring Boot ships a **BOM** (bill of materials), `spring-boot-dependencies`, that pins consistent, tested versions for hundreds of libraries. There are two ways to consume it in Gradle. The legacy way is the separate `io.spring.dependency-management` plugin, which the Boot plugin auto-imports the BOM into; it adds Maven-style `dependencyManagement {}` and lets you write versionless dependencies. The modern, **recommended** way uses Gradle's native BOM support: `implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.0"))`, which imports the same BOM as a Gradle *platform* with no extra plugin. Either way, you declare `implementation("org.springframework.boot:spring-boot-starter-web")` with no version and the BOM supplies it. You can override a managed version (e.g. set `ext["slf4j.version"]`) when you need to bump one library, keeping the rest aligned.
code
kotlin · 13 linesplugins {
java
id("org.springframework.boot") version "3.3.0"
}
dependencies {
// Native Gradle BOM import — no extra plugin
implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.0"))
implementation("org.springframework.boot:spring-boot-starter-web") // no version
implementation("org.springframework.boot:spring-boot-starter-actuator")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}go deeper
Know that the BOM lets you omit versions and that starters resolve to consistent versions.
Distinguish the native platform() import from the io.spring.dependency-management plugin and explain BOM constraints vs dependencies.
Articulate why platform() aligns with Gradle conflict resolution, how to override a single managed version, and the migration off the legacy plugin.
Standardize version governance across many modules (a shared internal platform/BOM, enforcedPlatform for hard pins, supply-chain and upgrade cadence policy).
## The problem BOMs solve Spring Boot pulls in a large, interlocking set of libraries (Jackson, Tomcat, Hibernate, SLF4J, …). Mixing incompatible versions causes subtle runtime failures. A **BOM** (bill of materials) is a published artifact that declares a curated, mutually-tested set of versions. Importing it lets you omit versions on your dependency declarations and trust the BOM to keep them consistent. ## Two mechanisms in Gradle **1. Native Gradle platform (recommended)** Gradle understands BOMs directly via the `platform()` dependency notation. No extra plugin needed: ```kotlin dependencies { implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.0")) implementation("org.springframework.boot:spring-boot-starter-web") } ``` The platform contributes *constraints*, not dependencies. Constraints influence version selection during resolution but don't pull anything in themselves. Because they're constraints, they participate in Gradle's normal conflict resolution. **2. The io.spring.dependency-management plugin (legacy)** This third-party plugin emulates Maven's `<dependencyManagement>` semantics. When the Spring Boot plugin detects it's applied, it auto-imports the Boot BOM into it: ```kotlin plugins { id("org.springframework.boot") version "3.3.0" id("io.spring.dependency-management") version "1.1.5" } ``` Now versionless dependencies resolve against the imported BOM. Unlike platform constraints, this plugin applies Maven-style *forced* version management: a managed version wins over transitive versions, which is closer to Maven but **diverges from Gradle's native conflict resolution**. That subtle difference is the main reason the platform approach is now preferred. ## Overriding a managed version To bump a single library while keeping the rest aligned: ```kotlin extra["slf4j.version"] = "2.0.13" // with the dependency-management plugin // or, with native platforms, use a dependency constraint: dependencies { constraints { implementation("org.slf4j:slf4j-api:2.0.13") } } ``` ## Why versionless starters work `spring-boot-starter-web` and friends are declared with versions in the BOM. Importing the BOM means you reference the starter by group:artifact only, and resolution fills in the BOM's version — giving you a coherent, supported dependency set per Boot release.
- Why is platform() now preferred over the io.spring.dependency-management plugin?platform() contributes Gradle dependency constraints that participate in Gradle's native conflict resolution and dependency graph, whereas the plugin applies Maven-style forced management that overrides transitive versions and behaves differently from the rest of a Gradle build — leading to surprises and harder upgrades.
- How do you override exactly one managed dependency version?With the plugin, set the BOM property, e.g. extra["jackson.version"] = "2.17.1". With native platforms, add a dependency constraint pinning that artifact's version. Both keep all other versions aligned to the BOM.
- Does importing the BOM pull in any dependencies?No. A platform/BOM only contributes version constraints (or managed versions). You still must declare the actual dependencies you use; the BOM just decides which versions they resolve to.
saying these in an interview costs you the question
- Saying the BOM downloads all Spring libraries
- Confusing platform() (constraints) with enforcedPlatform() (forced)
- Claiming the dependency-management plugin is required in modern Boot 3.x builds