Spring Boot
Spring Boot DevTools
Spring Boot DevTools is a set of development-time tools that dramatically speed up the inner development loop. Automatic application restart, LiveReload browser refresh, and development-friendly property defaults combine to make the edit-save-test cycle as fast as possible without sacrificing the full Spring Boot runtime.
What DevTools Does
Spring Boot DevTools is a development-only module that activates a set of features designed to make the development experience faster and more productive. It has four main capabilities:
Automatic restart — When files on the classpath change (a Java class is recompiled, a resource is modified), DevTools restarts the application automatically. This restart is dramatically faster than a full JVM restart because DevTools uses two classloaders — one for libraries (unchanged, never reloaded) and one for your application code (reloaded on change). Restart typically takes 1-2 seconds instead of 10-20 seconds.
LiveReload — DevTools starts an embedded LiveReload server. When the application restarts, the LiveReload server notifies the browser to refresh automatically. Install the LiveReload browser extension to enable this.
Development property defaults — DevTools activates a set of property defaults optimized for development: template caching disabled, web logging enabled, H2 console enabled. These override application.properties for the development session.
Remote DevTools — DevTools can be configured to restart a remote application over HTTP — useful for remote development environments or cloud-hosted development instances.
Adding DevTools
DevTools is added as an optional, runtime-scoped dependency. The optional flag prevents it from being transitively included in other projects. Spring Boot automatically disables it when running from a fully packaged JAR in production.
XML
<!-- Maven — add to pom.xml: -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
// Gradle — add to build.gradle:
// developmentOnly 'org.springframework.boot:spring-boot-devtools'
// DevTools is automatically DISABLED when:
// 1. Running from a packaged JAR: java -jar myapp.jar
// 2. Running via a special classloader (production app servers)
// 3. The property spring.devtools.restart.enabled=false is set
// DevTools is ENABLED when:
// - Running from an IDE (IntelliJ, Eclipse, VS Code)
// - Running via mvn spring-boot:run or ./gradlew bootRun
// - The dependency is on the classpath AND the app is not packaged
// Verify DevTools is active — look for this in startup logs:
// INFO --- [ restartedMain] c.e.myapp.MyappApplication : Started MyappApplication
// Note "restartedMain" thread name — indicates DevTools is runningAutomatic Restart — How It Works
DevTools' automatic restart is far faster than a cold start because it reloads only the classloader containing your application code — not the classloader containing libraries, which never changes during development.
Java
// DevTools uses TWO classloaders:
//
// Base classloader (never reloaded):
// - All JAR files from Maven/Gradle dependencies
// - Spring Framework, Hibernate, Jackson, etc.
// - Anything that doesn't change during development
//
// Restart classloader (reloaded on every change):
// - Your application classes (com/example/myapp/**)
// - Your resources (application.properties, templates, etc.)
//
// When a file changes:
// 1. DevTools detects the classpath change
// 2. Discards the restart classloader
// 3. Creates a new restart classloader
// 4. Restarts the Spring ApplicationContext
// 5. Binds the embedded server to the same port
//
// Result: 1-2 second restart vs 10-20 second cold start
// Configure restart behavior in application.properties:
spring.devtools.restart.enabled=true // true by default
spring.devtools.restart.poll-interval=1s // how often to check for changes
spring.devtools.restart.quiet-period=400ms // wait after last change before restarting
// Watch additional directories not on the default classpath:
spring.devtools.restart.additional-paths=src/main/groovy
// Exclude paths from triggering restart (changes to these paths don't restart):
spring.devtools.restart.exclude=static/**,public/**,templates/**
// These are already excluded by default — static files don't need a restart
// Add to the default exclusions:
spring.devtools.restart.additional-exclude=data/**
// Trigger a restart programmatically:
// (useful in tests or scripts)
import org.springframework.boot.devtools.restart.Restarter;
Restarter.getInstance().restart();Triggering Restart in Your IDE
DevTools watches the classpath for changes. The classpath changes when your IDE compiles your source files. Different IDEs handle this differently.
Java
// IntelliJ IDEA — two options:
// Option 1 — Manual build (default):
// Save a file → IntelliJ does NOT auto-compile by default
// Press Ctrl+F9 (Build Project) → classpath changes → DevTools restarts
// Or: Build menu → Build Project
// Option 2 — Enable auto-compile (recommended with DevTools):
// Settings → Build, Execution, Deployment → Compiler
// Check: "Build project automatically"
// Then: Settings → Advanced Settings
// Check: "Allow auto-make to start even if developed application is currently running"
// Now: Save a file → IntelliJ compiles → DevTools restarts automatically
// Eclipse — auto-compile is on by default:
// Save a file (Ctrl+S) → Eclipse compiles → DevTools restarts immediately
// No additional configuration needed
// VS Code with Spring Boot Extension Pack:
// Enable auto-save: File → Auto Save
// The Java Language Server compiles on save → DevTools restarts
// Or use the Spring Boot Dashboard to manually restart
// Maven command line — DevTools works with spring-boot:run:
// mvn spring-boot:run
// Edit a file, press Ctrl+F9 in IDEA to trigger compile
// DevTools detects the compiled .class change and restarts
// Gradle:
// ./gradlew bootRun
// Same behavior as MavenLiveReload
LiveReload automatically refreshes the browser when the application restarts. DevTools embeds a LiveReload server that communicates with a browser extension.
Java
// Setup:
// 1. Add DevTools dependency (already done)
// 2. Install LiveReload browser extension:
// - Chrome: search "LiveReload" in Chrome Web Store
// - Firefox: search "LiveReload" in Firefox Add-ons
// 3. Start your Spring Boot application
// 4. Open http://localhost:8080 in the browser
// 5. Click the LiveReload extension button to enable it for this tab
// 6. Edit a Thymeleaf template or static file → browser refreshes automatically
// LiveReload runs on port 35729 by default:
spring.devtools.livereload.enabled=true // true by default
spring.devtools.livereload.port=35729 // change if port is in use
// Disable LiveReload (keep restart, disable browser refresh):
spring.devtools.livereload.enabled=false
// What triggers a LiveReload browser refresh:
// - Application restart (after any Java class change)
// - Static file change (CSS, JS, images in src/main/resources/static/)
// - Template change (Thymeleaf, Freemarker in src/main/resources/templates/)
// For pure frontend work (changing CSS/JS only):
// Static files in src/main/resources/static/ are served directly
// Changes to them trigger LiveReload WITHOUT an application restart
// (because static/** is excluded from restart triggers by default)
// Template caching is disabled by DevTools automatically:
// spring.thymeleaf.cache=false
// spring.freemarker.cache=false
// spring.mustache.servlet.cache=false
// So template changes reflect immediately after LiveReload refreshDevelopment Property Defaults
When DevTools is active, it applies a set of property defaults optimized for development. These override any values in your application.properties for the local development session, without modifying your configuration files.
Java
// Properties DevTools sets automatically in development:
// (These are the defaults — you can override them in application.properties)
// Template caching — disabled so changes reflect without restart:
// spring.freemarker.cache=false
// spring.groovy.template.cache=false
// spring.mustache.servlet.cache=false
// spring.thymeleaf.cache=false
// spring.web.resources.cache.period=0
// spring.web.resources.chain.cache=false
// Web logging — more verbose in development:
// logging.level.web=DEBUG
// spring.mvc.log-resolved-exception=true
// H2 console — enabled when H2 is on the classpath:
// spring.h2.console.enabled=true
// Access at: http://localhost:8080/h2-console
// Actuator — all endpoints enabled in development:
// management.endpoints.web.exposure.include=*
// To see all DevTools property defaults:
// DevToolsPropertyDefaultsPostProcessor.java in Spring Boot source
// Or run with debug=true and look for "DevTools" in the conditions report
// Override a DevTools default in your application.properties:
spring.thymeleaf.cache=true // re-enable template caching even in dev
logging.level.web=INFO // reduce web logging verbosity
// DevTools defaults are applied BEFORE your application.properties
// so your properties WIN if they conflict with DevTools defaultsGlobal DevTools Configuration
DevTools settings can be placed in a global configuration file in your home directory — applying to all Spring Boot projects on the machine without modifying any project's application.properties.
application.properties
// Global DevTools config file location:
// ~/.spring-boot-devtools.properties (Unix/macOS)
// C:\Users\{username}\.spring-boot-devtools.properties (Windows)
// Settings in this file apply to ALL Spring Boot apps with DevTools on this machine:
// Global restart exclusions (don't restart when these change in ANY project):
spring.devtools.restart.exclude=static/**,public/**
// Disable LiveReload globally:
spring.devtools.livereload.enabled=false
// Project-level settings in application.properties OVERRIDE global settings
// Global → DevTools defaults → application.properties → command-line args
// Useful global settings:
spring.devtools.restart.poll-interval=2s // check less frequently
spring.devtools.restart.quiet-period=1s // longer quiet period
spring.devtools.livereload.port=35730 // different LiveReload portRemote DevTools
Remote DevTools allows you to push code changes to a remote Spring Boot application — useful when developing against a cloud-hosted or Docker-based development environment.
Java
// Step 1 — Enable remote support on the server (application.properties):
spring.devtools.remote.secret=my-remote-secret
// WARNING: Never enable remote DevTools in production
// Remote DevTools has security implications — only use in isolated dev environments
// Step 2 — Build and deploy the app WITH DevTools included:
// Remote DevTools requires DevTools on the server classpath
// By default, Spring Boot Maven plugin excludes DevTools from the JAR
// To include it, configure the plugin:
// pom.xml:
// spring-boot-maven-plugin configuration:
// excludeDevtools: false
// Step 3 — Run the remote client locally:
// Create a run configuration in your IDE that runs:
// org.springframework.boot.devtools.RemoteSpringApplication
// with the remote URL as the argument: https://myapp-dev.example.com
// Or run from Maven:
// mvn spring-boot:run -Dspring-boot.run.main-class=org.springframework.boot.devtools.RemoteSpringApplication -Dspring-boot.run.arguments=https://myapp-dev.example.com
// What remote DevTools does:
// - Watches local classpath for changes
// - Uploads changed classes to the remote server via HTTP tunnel
// - Triggers a restart on the remote server
// - Forwards LiveReload notifications to local browser
// Remote DevTools tunnel endpoints on the server:
// /.~~spring-boot!~/restart ← restart trigger
// /.~~spring-boot!~/livereload ← livereload server proxyDevTools in Practice — Common Workflows
These are the real development workflows where DevTools provides the most value — and the cases where its limitations matter.
Java
// WORKFLOW 1 — Fast backend iteration:
// 1. Start app once: mvn spring-boot:run
// 2. Edit UserService.java — fix a bug or add a method
// 3. Press Ctrl+F9 in IntelliJ (build)
// 4. DevTools detects .class change → restarts in ~1.5 seconds
// 5. Re-test the endpoint — no manual restart needed
// WORKFLOW 2 — Frontend template iteration:
// 1. Start app with DevTools and LiveReload browser extension active
// 2. Edit src/main/resources/templates/users/list.html
// 3. Save the file
// 4. Browser refreshes automatically — template cache is disabled
// 5. No restart needed for template-only changes
// WORKFLOW 3 — Static asset iteration:
// 1. Edit src/main/resources/static/css/style.css
// 2. Save — static/** is excluded from restart trigger
// 3. Browser refreshes via LiveReload without application restart
// Fastest workflow — no restart, just browser refresh
// CASES WHERE DEVTOOLS RESTART IS NOT ENOUGH:
// - Changing @Bean definitions in @Configuration classes
// → Restart works but context is fully rebuilt for config changes
// - Adding new dependencies to pom.xml
// → Must do a full Maven reload and restart — DevTools can't load new JARs
// - Changing application.properties
// → Restart picks up the new values automatically — this works fine
// - Changing Flyway migration scripts
// → Must either rollback the migration manually or reset the DB schema
// DISABLING DEVTOOLS FOR A SPECIFIC TEST:
@SpringBootTest
@TestPropertySource(properties = "spring.devtools.restart.enabled=false")
class MyIntegrationTest { }