Starters & Dependencies
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.
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:
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:
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/@RequestMappingannotation 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 aDataSourcebean. - spring-boot-starter-security — Spring Security 6 with sensible HTTP security defaults. Every endpoint is protected by default; you configure access rules in a
SecurityFilterChainbean. - 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 totestso 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:
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:
You can also override a managed version by setting the corresponding property in your POM. For instance, to use a newer Jackson release:
Inspecting the Dependency Tree
After adding starters, run the Maven dependency tree to see exactly what was pulled in and to spot unwanted duplicates:
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.
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.