Spring Framework is the core: a container that creates and wires your objects (dependency injection), plus modules for web, data and testing. Spring MVC is one of those modules, the one for building web applications and REST APIs with @Controller. Spring Boot is not a different framework. It is a layer on top that configures Spring for you, with sensible defaults, an embedded server and starters.
| Spring Framework | Spring MVC | Spring Boot | |
|---|---|---|---|
| What it is | Core container and modules | Web module of the framework (spring-webmvc) | Auto-configuration, starters and packaging on top of the framework |
| You use it to | Wire objects, add transactions, AOP, data access | Handle HTTP requests with controllers | Get a running app with almost no setup |
| Needs a separate server? | Not a web server | Yes, unless you embed one yourself | No: Tomcat is embedded by default |
| Configuration | You write it | You write it (@EnableWebMvc, servlet setup) | Mostly automatic; override what you need |
Tested on Spring Boot 4.1.1 / Spring Framework 7.0.9 / Tomcat 11.0.24, OpenJDK 21.0.12. I built the same /api/items endpoint twice and measured both: plain Spring MVC (PlainMvcDemo.java) and Spring Boot (DemoApplication.java). Startup times are from this sandbox and only meaningful relative to each other.
How the three fit together
Read the picture from the inside out. spring-core, spring-beans and spring-context are the container. spring-webmvc sits in the same framework and adds the DispatcherServlet that routes requests to your controllers. Boot wraps all of it and decides which pieces to switch on, based on what is on your classpath.
The same endpoint, without Boot
This is a complete plain Spring MVC server. You create the Spring context, create Tomcat, register the DispatcherServlet and map it to /:
package plain;
import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import java.io.File;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.bind.annotation.*;
import java.util.List;
public class PlainMvcDemo {
public static void main(String[] args) throws Exception {
long t0 = System.currentTimeMillis();
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(WebConfig.class); // you register the config yourself
Tomcat tomcat = new Tomcat(); // you create the server yourself
tomcat.setBaseDir(new File("target/tomcat").getAbsolutePath());
tomcat.setPort(8081);
tomcat.getConnector();
Context web = tomcat.addContext("", new File(".").getAbsolutePath());
Tomcat.addServlet(web, "dispatcher", new DispatcherServlet(ctx)).setLoadOnStartup(1);
web.addServletMappingDecoded("/", "dispatcher"); // you map the DispatcherServlet yourself
tomcat.start();
System.out.println("PLAIN started in " + (System.currentTimeMillis() - t0) + " ms, beans: " + ctx.getBeanDefinitionCount());
tomcat.getServer().await();
}
}
@Configuration
@EnableWebMvc // turns on Spring MVC: handler mapping, message converters, ...
@ComponentScan("plain")
class WebConfig { }
@RestController
@RequestMapping("/api")
class ItemController {
@GetMapping("/items")
List<String> items() { return List.of("pen", "book", "lamp"); }
}Source: PlainMvcDemo.java. It answers on port 8081 and printed this on its first run:
plain run 1: PLAIN started in 1546 ms, beans: 33The same endpoint, with Boot
The Boot version of the server is this class. Everything in PlainMvcDemo.main above is done by SpringApplication.run and auto-configuration:
package demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}Source: DemoApplication.java. The controller is the same kind of one-method class in both projects.
What the numbers say
Same endpoint, same machine, three runs each. The Boot app also carries starter-validation (it is the annotations demo), which accounts for part of the extra libraries, so read the library count as an upper bound.
plain run 1: PLAIN started in 1546 ms, beans: 33
plain run 2: PLAIN started in 1588 ms, beans: 33
plain run 3: PLAIN started in 1712 ms, beans: 33
boot run 1: Started DemoApplication in 2.416 seconds, beans: total beans in context: 160
boot run 2: Started DemoApplication in 2.53 seconds, beans: total beans in context: 160
boot run 3: Started DemoApplication in 2.606 seconds, beans: total beans in context: 160
plain jar: 14919318 bytes, 16 runtime deps
boot jar: 21575825 bytes, 40 libs (includes starter-validation)
lines (Main+WebConfig, plain): 37; lines (DemoApplication, boot): 11| Plain Spring MVC | Spring Boot | |
|---|---|---|
| Startup (median of 3) | 1588 ms | 2.53 s |
| Beans in the context | 33 | 160 |
| Runtime libraries | 16 | 40 (includes validation) |
| Executable jar | 14.9 MB | 21.6 MB |
| Lines to start a server | 37 (PlainMvcDemo.java main + config) | 11 (DemoApplication.java) |
Boot starts about a second slower here because it creates about five times as many beans: that is the price of auto-configuration. To see where startup time goes, read Why Your Spring Boot App Takes 8 Seconds to Start: A Bean-by-Bean Diagnosis. In exchange you get the error format below and everything else Boot wires without being asked.
What Boot decided for you
Ask both servers for a URL that does not exist. Plain MVC returns Tomcat’s HTML error page; Boot installed an error handler and returns JSON:
$ curl localhost:8081/nope (plain, title and status only)
HTTP 404 content-type=text/html;charset=utf-8
<title>HTTP Status 404 – Not Found</title>
$ curl localhost:8080/nope (boot)
{"timestamp":"2026-10-21T16:06:23.589Z","status":404,"error":"Not Found","path":"/nope"} HTTP 404 content-type=application/jsonSource: PlainMvcDemo.java and DemoApplication.java. That is the pattern: Boot picks a default for each thing you would otherwise configure by hand (JSON converter, error handling, server, logging) and gets out of the way when you define your own bean. See the annotations list for the annotations involved, and Write Your Own Spring Boot 4 Starter: Auto-Configuration, @Conditional and Properties to see how auto-configuration is written.
Which one should you use?
Use Spring Boot for a new application. Reach for plain Spring MVC only when you must deploy into an existing application server or need to control every piece. “Spring MVC vs Spring Boot” is not a choice between alternatives: a Boot web app is a Spring MVC app with the setup done for you.
The build files
Plain Spring MVC pom.xml (you pin every version)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>plain</groupId><artifactId>plain</artifactId><version>1.0.0</version>
<properties><maven.compiler.release>21</maven.compiler.release><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties>
<dependencies>
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>7.0.9</version></dependency>
<dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-core</artifactId><version>11.0.24</version></dependency>
<dependency><groupId>tools.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>3.1.5</version></dependency>
</dependencies>
<build><plugins>
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.6.0</version>
<executions><execution><phase>package</phase><goals><goal>shade</goal></goals>
<configuration><transformers><transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"><mainClass>plain.PlainMvcDemo</mainClass></transformer></transformers>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters><filter><artifact>*:*</artifact><excludes><exclude>META-INF/*.SF</exclude><exclude>META-INF/*.DSA</exclude><exclude>META-INF/*.RSA</exclude></excludes></filter></filters></configuration></execution></executions></plugin>
</plugins></build>
</project>Source: plain-spring-mvc-pom.xml. The versions come from what Boot 4.1.1 itself ships, listed in DemoApplication.java’s runtime jar: Spring 7.0.9, Tomcat 11.0.24, Jackson 3.1.5.
Spring Boot pom.xml (the parent manages versions)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.1</version>
<relativePath/>
</parent>
<groupId>demo</groupId>
<artifactId>demo</artifactId>
<version>1.0.0</version>
<properties><java.version>21</java.version></properties>
<dependencies>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webmvc</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
</dependencies>
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>Source: spring-boot-annotation-demo-pom.xml. No version appears on any dependency: spring-boot-starter-parent supplies them.
Common interview questions
What is the difference between Spring and Spring Boot?
Spring is the framework (container, MVC, data, AOP). Spring Boot configures Spring automatically, bundles an embedded server and gives you starters and production features.
What is the difference between Spring MVC and Spring Boot?
Spring MVC is the web module (DispatcherServlet, controllers). Spring Boot sets it up automatically; a Boot web app uses Spring MVC underneath.
Does Spring Boot replace Spring?
No. It depends on Spring Framework and adds auto-configuration on top. The libraries in the Boot jar above include spring-webmvc-7.0.9.jar.
Can you use Spring MVC without Spring Boot?
Yes. The plain version above does it with about 37 lines and a manually created Tomcat.
Why does Spring Boot start slower?
It creates more beans (160 vs 33 here) because auto-configuration registers defaults you did not write.
Common mistakes
- Treating them as three competing products. They are layers.
- Managing versions by hand. In plain Spring you pin every library version (see the plain pom); Boot’s parent pom does it for you.
- Adding
@EnableWebMvcinside a Boot app. It switches off Boot’s MVC defaults; leave it out unless you mean it. - Expecting
application.propertiesto work in plain Spring. Reading that file is Boot behaviour; plain Spring needs@PropertySource. - Comparing startup times without noting what is on the classpath. Beans, not magic, explain the difference.
FAQ
Is Spring MVC part of Spring Boot?
Spring MVC is part of Spring Framework. Boot’s spring-boot-starter-webmvc pulls it in and configures it.
Should beginners learn Spring or Spring Boot first?
Start with Boot to build something quickly, then learn the Spring concepts under it (beans, injection, MVC). The Spring Boot tutorial for beginners follows that order.
Which Spring Boot version should I use?
The latest GA with support left; see Spring Boot versions.
Further reading
- PlainMvcDemo.java and DemoApplication.java — the two servers compared
- Spring Boot tutorial for beginners
- Spring Boot annotations list
- Spring Boot versions and support dates
- Building Your First Spring RESTful API: A “Hello World” Guide
- Building a REST API with Spring Boot: Complete Beginner’s Guide
- Top 40 Spring MVC Interview Questions and Answers (2025)
- Dependency Injection in Spring Boot 4: Constructor vs Setter vs Field (and Why Field Injection Hurts)
- Top 40 Java Collections interview questions
- Top 40 Java concurrency interview questions
- Spring MVC reference documentation
No Comments yet!