Ch. 8 · Spring Boot

Spring vs Spring Boot: What Is the Difference?

Spring Framework provides dependency injection, MVC and transactions; Spring Boot sets it up with starters, auto-configuration and a server.

~6 min readbeginnerupdated Oct 20, 2026

Spring Framework is the foundation: the dependency injection container, Spring MVC for web requests, transaction management, AOP and data access support. Spring Boot is a layer on top of it that makes those pieces work with almost no setup. It chooses compatible library versions, configures beans automatically based on what’s on the classpath, embeds a web server so the app runs as a plain java -jar, and adds production features such as health checks and metrics.

So “Spring vs Spring Boot” isn’t a choice between two frameworks. Every Spring Boot application is a Spring application. You still write @Component classes, @RestControllers and @Transactional methods, and they run on the Spring Framework. Boot removes the configuration you’d otherwise write by hand. Candidates who describe Boot as “a faster Spring” or “Spring for microservices” give the wrong impression; the accurate phrase is “Spring with opinionated defaults”.

What each one gives you

Spring Framework Spring Boot
What it is The core framework Configuration and packaging layer on top of it
Dependency injection, MVC, transactions, AOP Yes Yes, the same Spring code
Choosing library versions You pick and align them Managed by Boot’s dependency BOM
Wiring infrastructure beans You declare DataSource, DispatcherServlet, view resolvers, Jackson setup Auto-configured from the classpath and properties
Web server Deploy a WAR to an external Tomcat, Jetty or similar Embedded Tomcat (or Jetty, Undertow), runs with java -jar
Configuration Whatever you build application.properties/.yml, profiles, environment variables, typed @ConfigurationProperties
Production features Add and wire yourself Actuator: health, metrics, info endpoints
Getting started Assemble the pieces Spring Initializr, one dependency per feature

Versions move together. At the time of writing, Spring Boot 4.1 requires Spring Framework 7 and Java 17 or newer; Spring Boot 3.x is built on Spring Framework 6. You don’t normally choose the Framework version in a Boot app, because Boot’s dependency management sets it.

The same endpoint, with and without Boot

To make the difference concrete, here’s a small JSON endpoint as a plain Spring MVC application. The code is illustrative (Spring Framework 6 and Jakarta Servlet APIs) and wasn’t run for this page, but it’s the standard setup.

// 1. Bootstrap the DispatcherServlet in a servlet container
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override protected Class<?>[] getRootConfigClasses()    { return null; }
    @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { WebConfig.class }; }
    @Override protected String[] getServletMappings()        { return new String[] { "/" }; }
}

// 2. Turn on Spring MVC and scan for controllers
@Configuration
@EnableWebMvc
@ComponentScan("com.example.shop")
public class WebConfig implements WebMvcConfigurer {
    // message converters, CORS, static resources, view resolvers: all yours to configure
}

// 3. The controller itself
@RestController
public class GreetingController {
    @GetMapping("/greeting")
    Map<String, String> greet() {
        return Map.of("message", "hello");
    }
}
java

On top of that you need a build that produces a WAR, explicit dependencies on spring-webmvc, a Jakarta Servlet API, and a Jackson version that works with your Spring version, plus a Tomcat installation to deploy into. When you later add a database, you also declare a DataSource, a transaction manager, an EntityManagerFactory and the JPA properties yourself.

The Boot version keeps the controller and replaces everything else with one class and one dependency (spring-boot-starter-web in Boot 3; Boot 4 renames it spring-boot-starter-webmvc and deprecates the old name):

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

./mvnw spring-boot:run starts Tomcat on port 8080, and GET /greeting returns {"message":"hello"}. The controller class is identical in both versions. That’s the point to make in an interview: Boot didn’t change how you write Spring code, it changed how much code you write around it.

What Boot is doing for you

Four mechanisms account for most of the difference.

Starters. A starter is a dependency that pulls in a coherent set of libraries for one feature. spring-boot-starter-data-jpa brings Spring Data JPA, Hibernate, a connection pool (HikariCP) and the JDBC support. Boot’s parent POM or BOM fixes the versions of hundreds of libraries so they’re known to work together, which ends the “which Jackson goes with this Spring version” problem.

Auto-configuration. @SpringBootApplication includes @EnableAutoConfiguration. On startup Boot evaluates a list of auto-configuration classes, each guarded by conditions such as @ConditionalOnClass (is Hibernate on the classpath?), @ConditionalOnProperty and, most importantly, @ConditionalOnMissingBean (has the application already defined one?). If you add a database driver and set spring.datasource.url, a DataSource appears. If you declare your own DataSource bean, Boot backs off. Running the app with --debug prints the conditions evaluation report, which tells you which auto-configurations applied and why. Spring Boot auto-configuration and explicit overrides goes through this in detail.

Embedded server and executable jar. The Boot Maven or Gradle plugin packages the app, its dependencies and the server into one runnable jar. That fits containers well: the image just runs java -jar app.jar. You can still build a WAR for an external server by extending SpringBootServletInitializer.

Externalised configuration and Actuator. Properties come from application.yml, profile-specific files, environment variables and command-line arguments, in a documented order of precedence, so the same jar runs in every environment. Actuator adds /actuator/health, metrics through Micrometer and other operational endpoints.

Misconceptions worth correcting

  • “Spring Boot is faster than Spring.” At runtime it’s the same framework doing the same work. Startup includes evaluating auto-configuration conditions, which costs a little. Performance differences come from configuration choices, not from Boot itself.
  • “Boot means microservices.” Boot is equally suited to a single large application. It became popular alongside microservices because standalone jars are easy to deploy many times over.
  • “Boot hides things, so you lose control.” Every default can be overridden by a property, by defining your own bean, or by excluding an auto-configuration with @SpringBootApplication(exclude = ...) or spring.autoconfigure.exclude.
  • “You can’t use Boot with an existing app server.” You can, by producing a WAR. You just give up the embedded server.

When plain Spring Framework is still the right choice

Most new applications should use Boot. Plain Spring remains sensible in a few situations:

  • Writing a library. A shared library should depend on spring-context or spring-web and stay neutral about how the application is configured. If it needs Boot integration, ship a separate auto-configuration module, the way Spring’s own projects do.
  • Running inside an existing platform that already controls the servlet container, class loading and configuration, where Boot’s conventions would fight the host.
  • Maintaining a legacy application where migrating carries more risk than benefit right now.

Practice question: migrating a legacy app

Your team maintains a Spring MVC 5 application packaged as a WAR and deployed to a shared Tomcat 9 server. It has XML configuration for the DataSource, transaction manager and view resolver. Management asks you to “move it to Spring Boot”. What would you change, what stays the same, and what’s the biggest risk?

Answer

The business code stays: controllers, services, repositories, @Transactional methods and their tests are ordinary Spring and run unchanged on Boot (apart from the namespace issue below). What goes is the infrastructure configuration Boot can provide. Add the Boot parent or BOM and the relevant starters, create a @SpringBootApplication class, move connection settings into application.yml as spring.datasource.*, and delete the XML beans for the DataSource, transaction manager and view resolver, checking the conditions report to confirm Boot created equivalents. Keep any genuinely custom configuration as @Configuration classes; Boot will back off for those beans.

Do it in steps. A reasonable first step keeps WAR packaging with SpringBootServletInitializer, so operations can deploy it the same way, and only later switches to an executable jar.

The biggest risk is the jump in underlying versions. Current Boot is built on Spring Framework 6 or 7, which uses Jakarta EE, so every javax.servlet and javax.persistence import becomes jakarta.*, Tomcat 9 can’t run it (Tomcat 10.1 or newer is needed), and Java 17 is the minimum. Hibernate and other libraries move major versions at the same time. A careful answer suggests a migration branch, an automated tool such as OpenRewrite for the namespace change, and a full regression test run before anyone deletes the old XML.

Keep reading

More in Spring Boot

esc