Spring BootSpring Boot DevTools
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 running

Automatic 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 defaultstatic 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 Maven

LiveReload

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 refresh

Development 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 defaults

Global 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 port

Remote 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 proxy

DevTools 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 { }