Spring Boot’s auto-configuration is a bit like a really good sous chef who anticipates what ingredients you’ll need based on what you’ve already put in the pot.

Let’s see it in action. Imagine you’ve added the spring-boot-starter-web dependency to your project. When Spring Boot starts up, it scans your classpath. Seeing spring-boot-starter-web means it knows you probably want to build a web application. It then looks for specific configuration classes that are designed to enable web functionality.

Here’s a snippet of what that might look like internally. Spring Boot looks for a file named META-INF/spring.factories within the libraries on your classpath. For spring-boot-starter-web, you’d find an entry like this:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
# ... other web related auto-configurations

When Spring Boot finds WebMvcAutoConfiguration, it doesn’t just blindly enable it. It checks conditions. For WebMvcAutoConfiguration, it might check if a DispatcherServlet is not already configured manually, or if certain critical classes like HttpServletRequest are on the classpath. If these conditions are met, it registers a DispatcherServlet bean, a RequestMappingHandlerMapping, and other essential web components for you. You don’t have to write any of that XML or Java config yourself.

The core problem auto-configuration solves is boilerplate. Before Spring Boot, setting up a web application with Spring typically involved a lot of manual XML configuration to define servlets, view resolvers, exception handlers, and more. Auto-configuration aims to get you up and running with sensible defaults for common use cases, allowing you to focus on your application’s business logic rather than infrastructure setup.

Internally, it’s a sophisticated conditional configuration system. Each auto-configuration class is annotated with @Configuration, and importantly, @Conditional annotations. These annotations specify the criteria that must be met for the configuration to be applied. Common conditions include:

  • @ConditionalOnClass: Checks if a specific class is present on the classpath. (e.g., org.springframework.web.servlet.DispatcherServlet for web auto-configuration).
  • @ConditionalOnMissingBean: Checks if a bean of a certain type is not already defined in the application context. This is crucial for allowing you to override auto-configured beans with your own custom implementations.
  • @ConditionalOnProperty: Checks if a specific configuration property (defined in application.properties or application.yml) has a certain value or is present.
  • @ConditionalOnWebApplication: Checks if the application is running as a web application.

Let’s say you add spring-boot-starter-data-jpa. Auto-configuration will detect this and look for JpaBaseConfiguration and related classes. It will then check for the presence of JPA-related classes (javax.persistence.EntityManagerFactory) and potentially JDBC driver classes. If these conditions are met, it will automatically configure an EntityManagerFactory bean, a PlatformTransactionManager, and other necessary JPA infrastructure. If you also have spring-boot-starter-jdbc on your classpath, it will try to auto-configure a DataSource too, using HikariCP by default if available.

The beauty is that you can influence this. If you define your own DataSource bean, the @ConditionalOnMissingBean(DataSource.class) condition on the auto-configuration will prevent Spring Boot from creating its own, respecting your explicit definition. This is how you customize.

The system is designed to be additive and overrideable. Spring Boot loads auto-configuration classes from META-INF/spring.factories in the order they are specified. Later configurations can override earlier ones, and your own @Configuration classes will always take precedence over auto-configurations if you define beans with the same name or type, thanks to @ConditionalOnMissingBean.

When Spring Boot auto-configures a RestTemplate bean because you included spring-boot-starter-web and didn’t define your own RestTemplate, it’s not just creating a basic instance. It’s checking for other common libraries. If it finds Jackson on the classpath, it will configure MappingJackson2HttpMessageConverter for you, enabling JSON processing. If it finds JAXB, it might configure Jaxb2RootElementHttpMessageConverter. This is all happening without you writing a single line of configuration code, based on the presence of other libraries.

The most surprising thing is how this conditional logic, combined with the ability to discover beans from multiple spring.factories files across different JARs, creates an emergent system where a few starter dependencies can assemble a complex application context with dozens of beans, all without explicit user instruction. It’s a form of declarative dependency injection on a meta-level.

The next logical step after understanding auto-configuration is to explore how to customize it further using @EnableConfigurationProperties and custom @Configuration classes.

Want structured learning?

Take the full Spring-boot course →