Spring Boot Essentials

Starters & Dependencies

18 min Lesson 3 of 13

Starters & Dependencies

One of Spring Boot's most practical contributions is the concept of the starter POM. Instead of hunting through documentation to figure out which five libraries you need for a REST API — and then discovering mid-project that your versions are incompatible — you declare a single starter and Spring Boot pulls in a tested, compatible set for you. This lesson explains how starters work, what the most important ones provide, and how to understand and control the dependency graph they create.

What Is a Starter?

A starter is a regular Maven (or Gradle) dependency whose JAR contains almost no code of its own. Its only job is to declare transitive dependencies on the real libraries. When Maven or Gradle resolves spring-boot-starter-web, it fetches Spring MVC, the embedded Tomcat server, Jackson (JSON), validation support, and more — all at versions that Spring Boot's release team has verified work together.

The magic is in the BOM. Every Spring Boot project inherits from (or imports) spring-boot-starter-parent, which itself inherits from spring-boot-dependencies — a Bill of Materials that pins the version of every library Spring Boot ships with. Starters then reference those versions without repeating them. This is why you rarely write version numbers for Spring Boot starters in your own POM.

The Parent POM and BOM

When you generate a project from start.spring.io, the resulting pom.xml looks like this at the top:

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.0</version> <relativePath/> </parent>

This single declaration gives you: managed dependency versions for 300+ libraries, sensible Maven plugin defaults (compiler to Java 17+, resource filtering, etc.), and the property java.version ready to override. If your project already has its own parent POM, you can use the BOM as an import instead:

<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>3.3.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

The Most Important Starters

The table below lists the starters you will reach for in almost every project. Each adds a focused, compatible set of libraries.

  • spring-boot-starter — The core starter. Included automatically by all others. Brings in Spring Core, Spring Context (the IoC container you know from the Spring IoC tutorial), logging via Logback, and auto-configuration infrastructure.
  • spring-boot-starter-web — Spring MVC, embedded Tomcat 10, Jackson (JSON serialisation), and the @RestController/@RequestMapping annotation processing you need for REST APIs.
  • spring-boot-starter-data-jpa — Hibernate 6, Spring Data JPA (repositories, @Entity, JPQL), and the transaction infrastructure. Requires a JDBC driver starter or a DataSource bean.
  • spring-boot-starter-security — Spring Security 6 with sensible HTTP security defaults. Every endpoint is protected by default; you configure access rules in a SecurityFilterChain bean.
  • spring-boot-starter-validation — Hibernate Validator (the Jakarta Bean Validation 3.0 reference implementation). Enables @Valid, @NotNull, @Size, etc. on controller method parameters and domain objects.
  • spring-boot-starter-test — JUnit 5, Mockito, AssertJ, Spring Test, and @SpringBootTest. Automatically scoped to test so nothing leaks into your production artifact.
  • spring-boot-starter-actuator — Production-readiness endpoints (/actuator/health, /actuator/metrics, info, env, etc.) that integrate with monitoring tools like Prometheus.
  • spring-boot-starter-cache — Abstraction layer over caching providers. Add a provider like Caffeine or Redis and it wires automatically.
  • spring-boot-starter-data-redis — Lettuce (async Redis client) and Spring Data Redis template support.
  • spring-boot-starter-amqp — RabbitMQ integration via Spring AMQP and @RabbitListener.

Declaring Starters in Maven

Because the parent BOM manages versions, you declare starters without a <version> tag:

<dependencies> <!-- REST API --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- JPA + your chosen database driver --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <!-- Bean validation --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <!-- Tests (test scope only) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>

Swapping or Excluding Transitive Dependencies

Starters choose an opinionated default. Sometimes you need something different. For example, spring-boot-starter-web uses embedded Tomcat, but you might prefer Undertow for its non-blocking I/O or lower memory footprint. You exclude the default and add the alternative:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <!-- Add Undertow instead --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency>

You can also override a managed version by setting the corresponding property in your POM. For instance, to use a newer Jackson release:

<properties> <java.version>21</java.version> <jackson.version>2.17.1</jackson.version> </properties>
Override versions sparingly. The BOM represents a tested matrix. If you force a newer version of one library, you may introduce incompatibilities with others that Spring Boot's team hasn't tested. Always re-run your full test suite after a version override, and track why the override was necessary so you can remove it when the next Boot release catches up.

Inspecting the Dependency Tree

After adding starters, run the Maven dependency tree to see exactly what was pulled in and to spot unwanted duplicates:

mvn dependency:tree

Look for the CONFLICT and omitted for conflict with labels — they indicate that two starters pulled in different versions of the same library and Maven chose one. Usually Maven's nearest-wins rule picks the right one, but sometimes you need to declare an explicit version in your own POM to force a specific choice.

Use mvn dependency:tree -Dincludes=groupId:artifactId to filter the tree to a specific library and trace exactly which starter introduced it. This is invaluable when diagnosing classpath conflicts or unexpected transitive pulls.

Creating Your Own Starter (the Pattern)

If you build internal libraries used across multiple services, you can package them as custom starters following Spring Boot's convention: a library module named acme-spring-boot-autoconfigure and an optional thin acme-spring-boot-starter that just declares it as a dependency. The autoconfigure module registers auto-configuration classes in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (the Spring Boot 3 mechanism that replaced the old spring.factories file). This lets any project that puts your starter on the classpath get your beans wired automatically — the same way the official starters work.

Summary

Starters are curated dependency bundles backed by a Bill of Materials that guarantees version compatibility. Declare the starters you need, let the BOM manage versions, and use <exclusions> plus property overrides when you need to deviate from the defaults. Understanding this dependency model — not just knowing which starter to pick — is what lets you diagnose classpath problems, reduce artifact size, and make informed trade-offs as your application grows.