How to Run Spring Boot Without a Web Server

Introduction

Not every Spring Boot application serves HTTP. A command-line tool, a batch job or a message consumer has no use for an embedded Tomcat, yet one starts - and keeps the JVM running - as soon as a web starter is on the classpath, often brought in by a dependency for some other reason. This quick tip shows how to start Spring Boot without a web server, and how to check that none started.

Tested on Spring Boot 4.1.2, Spring Framework 7.0.10 and JDK 25.

Setting the web application type to none

Spring Boot decides from the classpath which kind of application context to create: with Spring MVC present it creates a servlet web context and starts the embedded server. The property spring.main.web-application-type=none overrides that decision: Spring Boot creates a plain application context and starts no web server, whatever is on the classpath.
application.properties - the short answer
spring.main.web-application-type=none

The three ways to turn the web server off

OptionWhen to use itLimit
Leave the web starter out: depend on spring-boot-starter instead of spring-boot-starter-webmvcThe application never serves HTTPA web starter that arrives through another dependency brings the server back
spring.main.web-application-type=noneThe web libraries are needed on the classpath but not the server, or only some deployments should run itNone - it can be set per profile, environment variable or command line
new SpringApplicationBuilder(App.class).web(WebApplicationType.NONE).run(args)The decision belongs in code, for example in a separate main class for a toolFixed at compile time; the property is easier to change

Checking whether a web server started

The example is a small console application. A CommandLineRunner prints the class of the application context Spring Boot created and the port of the web server: Spring Boot sets the property local.server.port when an embedded server has started. main() closes the application when the runner has finished, as console applications usually do, so that every run ends.
src/main/resources/application.properties
spring.main.banner-mode=off
logging.level.root=WARN
ConsoleApp.java
//ConsoleApp.java
package com.javabrahman.tips.noweb;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

@SpringBootApplication
public class ConsoleApp {

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

  @Bean
  CommandLineRunner report(ConfigurableApplicationContext context, Environment env) {
    return args -> {
      System.out.println("application context: " + context.getClass().getSimpleName());
      System.out.println("web server port:     " + env.getProperty("local.server.port", "none - no web server started"));
    };
  }
}
The first run has spring-boot-starter-webmvc on the classpath and no setting; the second sets the property on the command line; the third runs with only spring-boot-starter on the classpath.  OUTPUT with the web starter, no setting
application context: AnnotationConfigServletWebServerApplicationContext
web server port:     8080
 OUTPUT with the web starter and --spring.main.web-application-type=none
application context: AnnotationConfigApplicationContext
web server port:     none - no web server started
 OUTPUT with only spring-boot-starter on the classpath
application context: AnnotationConfigApplicationContext
web server port:     none - no web server started
Explanation of the output
  • With the web starter and no setting, Spring Boot created an AnnotationConfigServletWebServerApplicationContext and started Tomcat on port 8080 - in a console application that only needed to print two lines.
  • With --spring.main.web-application-type=none, the same classpath gave a plain AnnotationConfigApplicationContext, and local.server.port was never set: no server started. The web libraries are still on the classpath and usable in code.
  • Without the web starter, Spring Boot found no web framework and chose the plain context by itself.

Pitfalls

  • A web starter can arrive through another dependency. If a server starts although you never added a web starter, mvn dependency:tree shows which dependency brings it; the property switches the server off either way.
  • Without a web server, nothing keeps the JVM alive: it ends when the runners have finished and no other non-daemon thread is left. An application that should keep running, such as a message consumer, can set spring.main.keep-alive=true.
  • Older answers use spring.main.web-environment=false. That boolean property was replaced by spring.main.web-application-type in Spring Boot 2.0.
  • Actuator endpoints are then not reachable over HTTP, since there is no server to serve them.

Related Spring Boot tutorials

How Spring Boot decides what to configure from the classpath is in how Spring Boot auto-configuration worksClick to read tutorial: How Spring Boot Auto-Configuration Works, and what each starter brings in Spring Boot starters explainedClick to read tutorial: Spring Boot Starters Explained with Examples.