skip to content

You import spring-boot-dependencies as a BOM (scope=import) instead of using spring-boot-starter-parent. How do you override a managed version now, and why is it different?

level: middleimportance: should knowfreq 45%

answer

  1. Imported BOM => property override does NOT work
  2. Add own dependencyManagement entry BEFORE the Boot import
  3. Imported BOMs: first-declared-wins
  4. Explicit <version> in <dependencies> always overrides
  5. Import the newer inner BOM (jackson-bom) first

basics

~10 s

Property overrides no longer work. Add your own <dependencyManagement> entry with the desired version, declared BEFORE the imported spring-boot-dependencies BOM. Maven's 'first declaration wins' for imported BOMs makes your entry take precedence.

solid answer

~40 s

With the parent, versions are properties you can redefine. But when you import spring-boot-dependencies as a BOM (<scope>import</scope>), you can't override those versions with properties — the properties are resolved inside the imported POM, not your project. Instead you add an explicit <dependencyManagement> entry for the artifact with the version you want, and place it **before** the spring-boot-dependencies import. Maven resolves dependency management using nearest/first-declared-wins among imported BOMs and local management, so a management entry in your own POM (or an earlier import) beats the imported Boot BOM. You can also just declare an explicit <version> on the dependency in <dependencies>, which always overrides managed versions. Either way you've stepped off the tested set.

code

xml · 19 lines
xml
<dependencyManagement>
  <dependencies>
    <!-- Override wins because it's declared first -->
    <dependency>
      <groupId>com.fasterxml.jackson</groupId>
      <artifactId>jackson-bom</artifactId>
      <version>2.18.1</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>3.3.2</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

go deeper

for a junior

Know that there are two ways to consume Boot's versions: parent (inherit) vs BOM (import).

for a middle

Know that with imported BOM you override via your own dependencyManagement placed before the Boot import, because property override no longer applies.

for a senior

Explain Maven's first-declared-wins for imported BOMs and when to import an inner BOM vs pin a single artifact.

for a principal

Standardize consumption model across many services (parent vs import) and codify override placement/ordering to avoid silent version regressions.

## Two ways to consume Spring Boot's dependency management 1. **Inherit** from `spring-boot-starter-parent` (real Maven parent). Managed versions are properties you can redefine in your child `<properties>`. 2. **Import** `spring-boot-dependencies` as a BOM: ```xml <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>3.3.2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ``` Teams import when they already have a corporate parent POM and can only inherit from one parent. ## Why property override stops working Maven property resolution for an **imported** BOM happens in the context of *that* POM, at import time. Redefining `<jackson-bom.version>` in *your* `<properties>` does not reach inside spring-boot-dependencies, so the imported management entries keep resolving to Boot's value. This is an explicit caveat in the Spring Boot reference documentation. ## The correct override for imported BOMs Add your own `<dependencyManagement>` entry and put it **before** the Boot import. For an artifact managed by an inner BOM (like Jackson), import the newer BOM first: ```xml <dependencyManagement> <dependencies> <!-- MUST come first so it wins --> <dependency> <groupId>com.fasterxml.jackson</groupId> <artifactId>jackson-bom</artifactId> <version>2.18.1</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>3.3.2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ``` For a single artifact you can instead list an explicit management entry: ```xml <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.13</version> </dependency> ``` ## Ordering rule Among imported BOMs, Maven uses **first-declared-wins** for a given managed artifact. So the override BOM/entry must precede spring-boot-dependencies. A dependency-management entry declared directly in your POM also outranks imported BOMs. ## The blunt hammer: explicit <version> on the dependency Declaring `<version>` directly in `<dependencies>` (not `<dependencyManagement>`) always overrides any managed version — with parent or imported BOM alike. It's the simplest override but only affects that one artifact and bypasses the coordinated BOM, so related modules can drift out of sync. ## Trade-off All of these move you off the exact set Boot tested. Prefer the smallest, most surgical override and document why (e.g. CVE fix).

  • Why must the override entry come before the spring-boot-dependencies import?
    For an imported BOM, Maven resolves a managed artifact's version to the FIRST matching declaration it encounters. If Boot's BOM is declared first, its version wins; putting your override first makes yours win.
  • Does an explicit <version> in the <dependencies> section behave differently from a <dependencyManagement> entry?
    Yes. A direct <version> in <dependencies> unconditionally sets that one artifact's version and beats all management. A <dependencyManagement> entry only supplies a default and interacts with import ordering, but can steer a whole inner BOM.

saying these in an interview costs you the question

  • Claiming property override works the same for imported BOM as for parent
  • Putting the override AFTER spring-boot-dependencies and expecting it to win
  • Thinking last-declared-wins for imported BOMs (it's first-wins)
  • Not realizing you can only inherit one Maven parent, which is why teams import

context