Spring BootSpring vs Spring Boot
Spring Boot

Spring vs Spring Boot

Spring Framework and Spring Boot are not competing technologies — Spring Boot is built on top of Spring Framework. But they solve different problems and make different trade-offs. Understanding the distinction explains why Spring Boot exists and when you'd choose one over the other.

The Relationship — Spring Boot IS Spring

Spring Boot is not a replacement for Spring Framework. It's built entirely on top of Spring Framework and uses all the same underlying mechanisms: the IoC container, dependency injection, AOP, Spring MVC, Spring Data, Spring Security — all of it. The difference is in how you configure and bootstrap those features. Spring Framework gives you the tools and leaves configuration entirely to you. Spring Boot provides opinionated defaults, auto-configuration, and starters that configure Spring Framework automatically based on what's on your classpath. Think of it this way: Spring Framework is the engine. Spring Boot is the car — the engine with transmission, steering, dashboard, and all the parts assembled so you can drive immediately, rather than assembling it yourself.

Configuration — Manual vs Automatic

The most fundamental difference between Spring and Spring Boot is configuration. Spring requires you to declare everything explicitly. Spring Boot infers and configures automatically.
XML
// ── Spring Framework — manual configuration ────────────────────────

// 1. web.xml (required for servlet container):
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

// 2. applicationContext.xml (Spring beans):
<context:component-scan base-package="com.example"/>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost/mydb"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven/>

// 3. dispatcher-servlet.xml (MVC config):
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"/>
    <property name="suffix" value=".jsp"/>
</bean>

// ── Spring Boot — zero configuration ────────────────────────────────

@SpringBootApplication  // one annotation replaces all of the above
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// application.properties: spring.datasource.url=jdbc:mysql://localhost/mydb
// That's the equivalent of all the XML above.

Dependency Management

Managing dependencies manually in Spring Framework is error-prone — version conflicts between Spring modules, Jackson, Hibernate, and other libraries cause hours of debugging. Spring Boot's parent POM solves this entirely.
XML
<!-- Spring Framework — manual version management: -->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>6.0.11</version>  <!-- must manually keep in sync -->
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>6.0.11</version>  <!-- must match spring-core -->
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>6.0.11</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>6.2.7.Final</version>  <!-- must be compatible with Spring 6 -->
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version>  <!-- must be compatible -->
    </dependency>
    <!-- 10+ more... -->
</dependencies>

<!-- Spring Boot — parent POM manages ALL versions: -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.1.4</version>
</parent>

<dependencies>
    <!-- One starter = all web dependencies at compatible versions: -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!-- No version — inherited from parent -->
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
</dependencies>

Deployment Model

Spring Framework applications are packaged as WAR files and deployed to an external application server. Spring Boot applications are self-contained JARs with an embedded server.
Java
// ── Spring Framework deployment ─────────────────────────────────
// 1. Package as WAR:     mvn package → myapp.war
// 2. Install Tomcat:     download, configure, start
// 3. Deploy WAR:         copy myapp.war to tomcat/webapps/
// 4. Tomcat URL:         http://localhost:8080/myapp/

// Drawbacks:
// - Must install and configure external server
// - Tomcat/server version must be managed separately
// - Context path in URL (/myapp) unless configured otherwise
// - WAR deployment means Tomcat classpath and app classpath interaction

// ── Spring Boot deployment ───────────────────────────────────────
// 1. Package as JAR:   mvn package → myapp.jar (fat JAR ~30MB)
// 2. Run:              java -jar myapp.jar
// 3. URL:              http://localhost:8080/

// Benefits:
// - No external server installation
// - Server version is a Maven dependency — controlled by you
// - Identical artifact runs in dev, staging, production
// - Works perfectly in Docker containers
// - Cloud-native by default (Kubernetes, Cloud Foundry, AWS)

// Spring Boot can still produce a WAR for legacy server deployment:
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(Application.class);
    }
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
// pom.xml: <packaging>war</packaging>

Feature Comparison at a Glance

A direct side-by-side comparison of the key differences:
Java
// Feature          Spring Framework          Spring Boot
// ──────────────────────────────────────────────────────────────────
// Configuration     Manual XML or Java config  Auto-configured by classpath
// Dependencies      Manual, version conflicts  Starters + parent POM
// Server            External (Tomcat, JBoss)   Embedded (Tomcat/Jetty/Undertow)
// Packaging         WAR                        JAR (fat JAR)
// Startup code      Extensive boilerplate      @SpringBootApplication + main()
// Properties        Multiple config files      Single application.properties
// Testing           Requires more setup        @SpringBootTest, @WebMvcTest
// Monitoring        Manual setup               Actuator included
// Learning curve    Steep                      Gentle
// Flexibility       Maximum — everything manual Opinionated — override when needed
// Use case          Legacy systems, fine-tuned control  New projects, microservices

// When to use Spring Framework directly:
// - Migrating a legacy XML-configured Spring application
// - Need granular control over every configuration detail
// - Building a library or framework, not an application

// When to use Spring Boot:
// - Starting a new project (always)
// - Building microservices
// - REST APIs
// - Batch processing
// - Event-driven applications
// Basically: new projects should always start with Spring Boot

Same Code, Different Bootstrap

The business logic code is identical between Spring and Spring Boot. The difference is only in bootstrapping. A service, repository, or controller written for Spring MVC works unchanged in Spring Boot.
Java
// This code is IDENTICAL whether you use Spring or Spring Boot:
@Service
@Transactional
public class UserService {

    private final UserRepository repository;

    public UserService(UserRepository repository) {
        this.repository = repository;
    }

    public User createUser(CreateUserRequest request) {
        if (repository.existsByEmail(request.email())) {
            throw new DuplicateEmailException(request.email());
        }
        return repository.save(new User(request.email(), request.name()));
    }
}

@RestController
@RequestMapping("/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public User createUser(@RequestBody @Valid CreateUserRequest request) {
        return userService.createUser(request);
    }
}

// The ONLY difference between Spring and Spring Boot is in:
// 1. The bootstrap class (how the application starts)
// 2. The pom.xml (starters vs manual dependencies)
// 3. The absence of XML configuration files in Spring Boot
// Your actual application logic: zero changes.