00:00

Spring Boot Auto-Configuration

Last updated:

Add one dependency to a Spring Boot project, start it, and a web server, a JSON converter or a database connection pool simply appears, without a single line of setup code. The feature behind this is auto-configuration, and it is the main reason Spring Boot applications need so little configuration.

This tutorial explains what auto-configuration does, how it decides what to create, how to change or switch off its choices, how to see exactly what it did, and how to write your own.

1. What Is Auto-Configuration?

Auto-configuration is Spring Boot’s ability to create and set up beans for you, based on three things:

  • The libraries on your classpath, which come from your dependencies.
  • The beans you have already defined yourself.
  • The properties you have set, for example in application.properties.

In one sentence: add a library, and Spring Boot configures it with sensible defaults, unless you have configured it yourself.

For example, adding spring-boot-starter-web leads Spring Boot to configure:

What gets configuredWhat it does
Embedded Tomcat serverListens for HTTP requests on port 8080
DispatcherServletRoutes each request to the right controller method
Jackson ObjectMapperConverts Java objects to and from JSON
HTTP message convertersRead request bodies and write response bodies
Error handlingProvides the default /error endpoint

2. Why Auto-Configuration Matters

Here is what connecting to a database looked like without auto-configuration. You had to build the connection pool yourself:

DatabaseConfig.java (without auto-configuration)
@Configuration
public class DatabaseConfig {

    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:postgresql://localhost:5432/shop");
        config.setUsername("shop_user");
        config.setPassword("secret");
        config.setMaximumPoolSize(10);
        return new HikariDataSource(config);
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    // ... plus a transaction manager, and more for JPA
}

With auto-configuration, that whole class disappears. You provide only the values that are specific to your application:

application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/shop
spring.datasource.username=shop_user
spring.datasource.password=secret

Spring Boot creates the connection pool, the JdbcTemplate and the transaction manager for you. Less code also means fewer places for mistakes, and the defaults follow good practice.

3. How Auto-Configuration Works, Step by Step

  1. Your application starts, and @SpringBootApplication switches on auto-configuration.
  2. Spring Boot first registers your own beans, found through component scanning.
  3. It then reads the list of candidate auto-configuration classes shipped inside the Spring Boot JARs, more than a hundred of them.
  4. For each candidate, it checks its conditions: Is a certain library present? Is a property set? Has the developer already defined this bean?
  5. Only the candidates whose conditions all pass are applied, and their beans are created.
  6. Your application starts with your beans plus the matching auto-configured ones.

Because your own beans are registered first, auto-configuration can see them and step back. That is how your configuration always wins.

4. @SpringBootApplication and @EnableAutoConfiguration

Every Spring Boot application starts from a class annotated with @SpringBootApplication:

ShopApplication.java
@SpringBootApplication
public class ShopApplication {

    public static void main(String[] args) {
        SpringApplication.run(ShopApplication.class, args);
    }
}

@SpringBootApplication is a shortcut for three annotations:

AnnotationRole
@SpringBootConfigurationMarks this as the main configuration class (a special form of @Configuration)
@ComponentScanFinds your own classes, such as controllers and services, in this package and below
@EnableAutoConfigurationSwitches auto-configuration on; this is the key one

You rarely need to write @EnableAutoConfiguration yourself, because @SpringBootApplication already includes it.

5. Where Auto-Configuration Classes Come From

Spring Boot does not scan for auto-configuration classes. Instead, each JAR lists its candidates in a plain text file:

Spring Boot versionFile that lists auto-configuration classes
2.6 and olderMETA-INF/spring.factories
2.7Either file (the new one was introduced; the old one still worked)
3.0 and laterMETA-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

The newer file simply contains one fully qualified class name per line:

AutoConfiguration.imports
com.example.audit.autoconfigure.AuditAutoConfiguration
com.example.audit.autoconfigure.AuditWebAutoConfiguration

Spring Boot’s own list lives in the spring-boot-autoconfigure JAR and includes classes such as DataSourceAutoConfiguration, WebMvcAutoConfiguration, JacksonAutoConfiguration and SecurityAutoConfiguration.

6. Inside an Auto-Configuration Class

An auto-configuration class is an ordinary configuration class with conditions attached. This simplified example shows the typical pattern Spring Boot uses:

SimpleDataSourceAutoConfiguration.java (simplified example)
// 1. Only if Hikari is on the classpath
@AutoConfiguration
@ConditionalOnClass(HikariDataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class SimpleDataSourceAutoConfiguration {

    // 2. Only if you have not defined a DataSource yourself
    @Bean
    @ConditionalOnMissingBean(DataSource.class)
    public DataSource dataSource(DataSourceProperties properties) {
        // 3. Use the values from spring.datasource.*
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(properties.getUrl());
        dataSource.setUsername(properties.getUsername());
        dataSource.setPassword(properties.getPassword());
        return dataSource;
    }
}

Read it like a set of rules:

  1. If the Hikari library is not on the classpath, skip the whole class.
  2. If you already defined a DataSource bean, skip this method and use yours.
  3. Otherwise, create a DataSource using the values from spring.datasource.*.

Spring Boot’s real DataSourceAutoConfiguration follows the same idea, with more cases. Classes are marked with @AutoConfiguration, introduced in Spring Boot 2.7; older code used @Configuration.

7. Conditional Annotations

Conditions are what make auto-configuration smart. Each one asks a yes-or-no question before a class or bean is applied:

AnnotationApplies when...Example use
@ConditionalOnClassA class is on the classpathConfigure Jackson only if Jackson is present
@ConditionalOnMissingClassA class is not on the classpathFall back to a simpler option
@ConditionalOnBeanA bean of a type already existsConfigure a JdbcTemplate only if a DataSource exists
@ConditionalOnMissingBeanNo bean of that type exists yetCreate a default unless you defined your own
@ConditionalOnPropertyA property has a certain valueA feature switch such as audit.enabled=true
@ConditionalOnWebApplicationThe app is a web applicationConfigure web-only beans
@ConditionalOnNotWebApplicationThe app is not a web applicationConfigure beans for command-line tools
@ConditionalOnResourceA file exists on the classpathLoad settings only if a config file is present
@ConditionalOnSingleCandidateExactly one bean of a type exists, or one is primaryPick the only DataSource automatically
@ConditionalOnJavaRunning on a certain Java versionUse a newer Java feature when available
@ConditionalOnExpressionA SpEL expression is trueComplex rules combining several properties

You can use the same annotations in your own configuration classes. For example, enable a feature only when a property says so:

NotificationConfig.java
@Configuration
public class NotificationConfig {

    @Bean
    @ConditionalOnProperty(name = "shop.notifications.sms.enabled", havingValue = "true")
    public SmsSender smsSender() {
        return new TwilioSmsSender();
    }

    @Bean
    @ConditionalOnMissingBean(SmsSender.class)
    public SmsSender noOpSmsSender() {
        return message -> { /* SMS disabled: do nothing */ };
    }
}

8. Customizing with Properties

The simplest way to change auto-configured behavior is a property. Most auto-configured beans read their settings from application.properties:

application.properties
# Web server
server.port=9090
server.servlet.context-path=/shop

# Connection pool tuning
spring.datasource.hikari.maximum-pool-size=20
# Hikari timeouts are in milliseconds
spring.datasource.hikari.connection-timeout=5000

# JSON output
spring.jackson.serialization.indent-output=true
spring.jackson.default-property-inclusion=non_null

Always try a property first. It keeps all the benefits of auto-configuration and changes only what you need. Your IDE can suggest the available property names as you type.

9. Overriding with Your Own Bean

When a property is not enough, define the bean yourself. Because auto-configured beans use @ConditionalOnMissingBean, Spring Boot sees yours and does not create its own:

DataSourceConfig.java
@Configuration
public class DataSourceConfig {

    @Bean
    public DataSource dataSource(Environment env) {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(env.getProperty("shop.db.url"));
        dataSource.setUsername(env.getProperty("shop.db.user"));
        dataSource.setPassword(env.getProperty("shop.db.password"));
        dataSource.setPoolName("shop-pool");
        return dataSource;
    }
}

Only the DataSource is replaced. Everything that depends on it, such as JdbcTemplate and the transaction manager, is still auto-configured, and now uses your bean.

10. Excluding an Auto-Configuration

To switch off an auto-configuration completely, exclude it. This is useful when a library is on the classpath but you do not want Spring Boot to configure it:

ShopApplication.java
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class ShopApplication {

    public static void main(String[] args) {
        SpringApplication.run(ShopApplication.class, args);
    }
}

Or exclude it with a property, which lets you do it for one profile only:

application-demo.properties
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
ApproachWhen to use it
Set a propertyYou want the auto-configured bean with different settings (try this first)
Define your own beanYou need full control over one bean, but want the rest auto-configured
Exclude the auto-configurationYou do not want that feature configured at all

11. Seeing What Was Applied

Auto-configuration never has to be a mystery. Start the application with --debug, or set debug=true, and Spring Boot prints a conditions evaluation report:

Terminal
java -jar target/shop.jar --debug
Console (shortened)
============================
CONDITIONS EVALUATION REPORT
============================

Positive matches:
-----------------

   DispatcherServletAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'
      - found 'session' scope (OnWebApplicationCondition)

Negative matches:
-----------------

   MongoAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'com.mongodb.client.MongoClient'
SectionMeaning
Positive matchesAuto-configurations that were applied, and why
Negative matchesAuto-configurations that were skipped, and which condition failed
ExclusionsAuto-configurations you excluded on purpose
Unconditional classesConfigurations applied without any condition

In a running application, Spring Boot Actuator shows the same report at /actuator/conditions, once you expose that endpoint. See the Spring Boot Actuator tutorial for setup.

12. Writing Your Own Auto-Configuration

Your own libraries can configure themselves too, just like Spring Boot’s. Imagine a shared audit library used by many services in your company. Instead of every service wiring it up by hand, the library configures itself when it is added as a dependency.

12.1 The properties

AuditProperties.java
package com.example.audit.autoconfigure;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "company.audit")
public record AuditProperties(
        boolean enabled,
        String applicationName
) {
    public AuditProperties {
        if (applicationName == null) {
            applicationName = "unknown-service";
        }
    }
}

12.2 The auto-configuration class

AuditAutoConfiguration.java
package com.example.audit.autoconfigure;

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

@AutoConfiguration
@EnableConfigurationProperties(AuditProperties.class)
@ConditionalOnProperty(prefix = "company.audit", name = "enabled", havingValue = "true", matchIfMissing = true)
public class AuditAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public AuditLogger auditLogger(AuditProperties properties) {
        return new AuditLogger(properties.applicationName());
    }
}

12.3 Register it

Create this file in the library’s src/main/resources folder:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.audit.autoconfigure.AuditAutoConfiguration

12.4 Use it in an application

A service now only adds the dependency and, optionally, a property. The AuditLogger bean is ready to inject:

application.properties
company.audit.application-name=order-service
OrderService.java
@Service
public class OrderService {

    private final AuditLogger auditLogger;

    public OrderService(AuditLogger auditLogger) { // provided by the library
        this.auditLogger = auditLogger;
    }

    public void cancel(Long orderId) {
        // ... cancel the order
        auditLogger.log("Order " + orderId + " cancelled");
    }
}

Setting company.audit.enabled=false switches the whole library off, and defining your own AuditLogger bean replaces the default one, exactly like Spring Boot’s own auto-configurations.

13. Ordering Auto-Configurations

Some auto-configurations depend on others. For example, an audit configuration that writes to the database needs the DataSource to be configured first. Declare the order on @AutoConfiguration:

AuditJdbcAutoConfiguration.java
@AutoConfiguration(after = DataSourceAutoConfiguration.class)
@ConditionalOnBean(DataSource.class)
public class AuditJdbcAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public AuditStore auditStore(DataSource dataSource) {
        return new JdbcAuditStore(dataSource);
    }
}

The after attribute guarantees that the DataSource conditions are evaluated first, so @ConditionalOnBean(DataSource.class) sees the result. There are also before and afterName/beforeName attributes, the last two taking class names as strings.

14. Testing Auto-Configuration

Spring Boot provides ApplicationContextRunner for testing auto-configurations. It starts a tiny application context in milliseconds, and lets you check which beans exist under different conditions:

AuditAutoConfigurationTest.java
class AuditAutoConfigurationTest {

    private final ApplicationContextRunner runner = new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(AuditAutoConfiguration.class));

    @Test
    void createsAuditLoggerByDefault() {
        runner.run(context -> assertThat(context).hasSingleBean(AuditLogger.class));
    }

    @Test
    void canBeSwitchedOffWithAProperty() {
        runner.withPropertyValues("company.audit.enabled=false")
              .run(context -> assertThat(context).doesNotHaveBean(AuditLogger.class));
    }

    @Test
    void backsOffWhenUserDefinesTheirOwnBean() {
        runner.withUserConfiguration(CustomLoggerConfig.class)
              .run(context -> assertThat(context.getBean(AuditLogger.class))
                      .isSameAs(context.getBean("customAuditLogger")));
    }

    @Configuration
    static class CustomLoggerConfig {
        @Bean
        AuditLogger customAuditLogger() {
            return new AuditLogger("custom");
        }
    }
}

These three tests cover the three promises every good auto-configuration makes: it works by default, it can be switched off, and it steps back for the user’s own bean.

15. Starters vs Auto-Configuration

Starters and auto-configuration are often mentioned together, but they do different jobs:

StarterAuto-configuration
What it isA dependency that bundles librariesCode that creates and configures beans
JobPuts the right libraries on the classpathReacts to those libraries and sets them up
ContainsMostly just a pom.xmlConfiguration classes with conditions
Examplespring-boot-starter-webWebMvcAutoConfiguration

They work as a team: the starter brings the libraries, and auto-configuration notices them and configures them. Read more about starters in the Spring Boot Introduction.

16. Common Mistakes to Avoid

MistakeWhat goes wrongFix
Excluding an auto-configuration when a property would doYou lose all its other useful defaultsTry a property or your own bean first
Guessing why a bean is missingHours of trial and errorRun with --debug and read the report
Putting your auto-configuration class in a scanned packageIt is applied as normal configuration, ignoring the intended orderKeep it outside component-scan packages and list it in the .imports file
Forgetting @ConditionalOnMissingBean in your own auto-configurationUsers cannot replace your beanAdd it to every bean users might want to override
Using @ConditionalOnBean in a normal @Configuration classThe result depends on bean registration order and may be wrongUse it only in auto-configuration classes, with proper ordering
Adding starters you do not needUnwanted features are configured and startup is slowerRemove unused dependencies

17. Summary

Auto-configuration is a set of ordinary configuration classes, listed inside Spring Boot’s JARs and guarded by conditions. At startup, Spring Boot checks each condition, such as which libraries are present, which beans you defined and which properties you set, and applies only the configurations that fit. You stay in control: change settings with properties, replace single beans with your own, exclude whole configurations, and use the conditions report to see exactly what happened.

Interview one-liner: Spring Boot auto-configuration creates beans automatically based on the classpath, existing beans and properties, using conditional annotations, and steps back whenever the developer provides their own configuration.