Skip to main content

Spring vs Spring Boot vs Spring MVC: What Is the Difference? (with Both Built and Measured)

Spring Framework, Spring MVC and Spring Boot explained by building the same endpoint twice: plain Spring MVC with manual Tomcat vs Spring Boot, with startup time, beans and jar size measured.

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 FrameworkSpring MVCSpring Boot
What it isCore container and modulesWeb module of the framework (spring-webmvc)Auto-configuration, starters and packaging on top of the framework
You use it toWire objects, add transactions, AOP, data accessHandle HTTP requests with controllersGet a running app with almost no setup
Needs a separate server?Not a web serverYes, unless you embed one yourselfNo: Tomcat is embedded by default
ConfigurationYou write itYou 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

Spring Boot: starters, auto-configuration, embedded server, Actuator, config filesSpring Framework: the container (beans, DI, AOP), data access, testingspring-corespring-beansspring-contextspring-aopSpring MVCspring-webmvc: DispatcherServlet,@Controller, @GetMapping(the web layer)spring-web, spring-aop,spring-expression, …(also: tx, jdbc, test,webflux as extra jars)

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: 33

The 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 MVCSpring Boot
Startup (median of 3)1588 ms2.53 s
Beans in the context33160
Runtime libraries1640 (includes validation)
Executable jar14.9 MB21.6 MB
Lines to start a server37 (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/json

Source: 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 @EnableWebMvc inside a Boot app. It switches off Boot’s MVC defaults; leave it out unless you mean it.
  • Expecting application.properties to 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

No Comments yet!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.