Mastering SpringBoot Dependency Management with BOM and Version Control
This article explains why SpringBoot projects need centralized dependency management, introduces the concept of a Maven/Gradle BOM, and walks through three practical scenarios—using the parent BOM, manually importing it, and overriding versions—while highlighting common pitfalls and best‑practice solutions.
Why Dependency Management Is Needed
SpringBoot projects depend on many libraries (Spring Core, Spring MVC, database drivers, Redis client, third‑party tools, etc.). Without a unified version strategy, three problems arise:
Version conflicts : manually adding Spring Core 5.3.20 while SpringBoot Web Starter 2.7.0 brings Spring 5.3.22, causing class‑loading failures.
Redundant or missing dependencies : transitive relationships (e.g., MyBatis depends on Spring JDBC) can lead to duplicate or omitted artifacts.
High maintenance cost : dozens of dependencies require individual version updates, which is error‑prone.
SpringBoot solves these issues with a BOM (Bill of Materials) that provides unified, compatible versions and simplifies configuration.
What Is a BOM?
A BOM is a special Maven/Gradle POM that defines a set of compatible dependency versions. It acts as a "version dictionary" so developers only need to import the BOM; the actual versions are resolved automatically.
SpringBoot’s BOM
The official SpringBoot BOM is spring-boot-dependencies, which lists compatible versions for the entire SpringBoot ecosystem (Spring, Spring MVC, Redis, MySQL driver, etc.). When a SpringBoot project uses the default parent POM, this BOM is already imported, which is why starter dependencies do not require explicit version numbers.
Core Usage Scenarios (Covering 99% of Needs)
Scenario 1: Use the SpringBoot Parent BOM
Creating a SpringBoot project automatically adds the parent spring-boot-starter-parent, which imports spring-boot-dependencies. You can then add starter dependencies without specifying versions.
<!-- Parent project that includes the SpringBoot BOM -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/>
</parent>
<!-- Add dependencies; versions are supplied by the BOM -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>Advantage: no manual version management; SpringBoot guarantees compatibility.
Scenario 2: Manually Import the BOM When the Parent Cannot Be Inherited
If a module cannot inherit spring-boot-starter-parent, import the BOM via the dependencyManagement section.
<!-- Manually import SpringBoot BOM for version control -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- Add dependencies without versions – they inherit from the BOM -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>Note: dependencyManagement only defines versions; you still need to list the actual dependencies under dependencies.
Scenario 3: Override BOM Versions
When a specific version is required (e.g., MySQL 8.0 while the BOM defaults to 5.7), you can override either locally in a dependency or globally via properties.
Method 1 – Local Override in a Dependency
<dependencies>
<!-- Override MySQL driver version defined in the BOM -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
</dependencies>Method 2 – Global Override via Properties
<properties>
<!-- Global override for MySQL driver version -->
<mysql.version>8.0.32</mysql.version>
<!-- Global override for Redis version -->
<redis.version>3.2.10</redis.version>
</properties>
<dependencies>
<!-- No version needed; the property value is used automatically -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>Using properties lets you change a version in one place, avoiding scattered overrides.
Key Features of SpringBoot BOM
Version unification : defines a compatible set of versions, preventing conflicts.
Simplified configuration : no need to specify versions for each dependency.
Overridable : you can manually set a version to replace the BOM default.
Transitivity : imported BOM versions apply to transitive dependencies (e.g., Spring Core version is controlled when you add spring-boot-starter-web).
Common Dependency‑Version Issues and Solutions
Dependency Conflicts
Symptoms: ClassNotFoundException, NoSuchMethodError, duplicate JARs.
Solution: Prefer the SpringBoot BOM; use Maven’s dependency tree view to locate conflicts and exclude unwanted artifacts:
<!-- Exclude a conflicting transitive dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>Incompatible Manual Versions
Wrong: arbitrarily mixing SpringBoot 2.7.0 with Spring 6.0.
Correct: if you must customize a version, ensure it matches the SpringBoot compatibility matrix (refer to the official docs).
Redundant Dependencies
Wrong: adding the same library multiple times or pulling in unnecessary artifacts.
Correct: rely on starter dependencies, which automatically bring in the required transitive libraries.
Summary
For typical projects, inherit the SpringBoot parent POM and let the BOM manage versions automatically.
If you cannot inherit the parent, import spring-boot-dependencies via dependencyManagement to gain the same version control.
When custom versions are needed, prefer global overrides through properties to keep the build clean and maintainable.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Tech Workshop
Focused on Java backend technologies, sharing fundamentals, multithreading, JVM, the Spring ecosystem, microservices, distributed systems, high concurrency, source‑code analysis, and practical experience. Continuously delivers high‑quality original content, interview guides, and learning roadmaps to help Java developers progress from beginner to advanced, enhancing technical skills and core competitiveness.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
