00:00

Spring Boot DevTools

While you build an application, you change code dozens of times an hour. Stopping the application, starting it again and refreshing the browser after every change adds up to a lot of waiting. Spring Boot DevTools removes most of that waiting: it restarts your application automatically when code changes, refreshes the browser for you, and switches on settings that make development easier.

This tutorial shows how to add DevTools, how its fast restart works, how to set up your IDE, how to control what triggers a restart, and how to make sure it never reaches production.

1. What Is Spring Boot DevTools?

Spring Boot DevTools is an optional module, spring-boot-devtools, that adds features for development only:

FeatureWhat it does for you
Automatic restartRestarts the application within seconds when compiled code changes
LiveReloadRefreshes the browser automatically when pages, CSS or JavaScript change
Development defaultsTurns off template and resource caching and shows more error details
Global settingsLets you keep personal DevTools settings in one file for all projects
Remote supportCan push changes to an application running on another machine

DevTools switches itself off when the application runs as a packaged production JAR, so it is safe to keep in your project.

2. Why You Need DevTools

Without DevToolsWith DevTools
Stop the app, start it again, wait for it to bootSave the file; the app restarts by itself in a second or two
Template changes need a restart because pages are cachedTemplate changes show on the next browser refresh
Refresh the browser by hand after every CSS changeLiveReload refreshes it for you
Hunt for hidden error detailsError responses include the message and details during development

Suppose a full start takes 10 seconds and you restart 60 times a day. That is 10 minutes of waiting, every day, just for restarts. DevTools restarts are typically much faster, and they happen without you having to do anything.

3. Adding DevTools to Your Project

For Maven, add the dependency as runtime and optional:

pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

For Gradle, use the special developmentOnly configuration:

build.gradle
dependencies {
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
}
SettingWhy it is there
runtime scopeYour code never refers to DevTools classes, so it is not needed for compiling
optional (Maven)Stops DevTools from passing on to other projects that depend on yours
developmentOnly (Gradle)Available when running locally, but never packaged into the final JAR

No configuration is needed. Run the application from your IDE or with ./mvnw spring-boot:run, and DevTools is active.

4. Automatic Restart

DevTools watches the classpath, the folders your IDE or build tool compiles into. When a file there changes, the application restarts automatically.

4.1 Why the restart is fast: two classloaders

A Java classloader is the part of the JVM that loads classes. DevTools splits your application across two of them:

ClassloaderLoadsOn restart
Base classloaderClasses that do not change: Spring, Hibernate, Jackson and all other library JARsKept as it is
Restart classloaderYour own classes and resources, the ones you are editingThrown away and created again

Because the large libraries stay loaded, only your own code is loaded again, which is why a DevTools restart is usually much quicker than a cold start.

4.2 What triggers a restart

  • Changed Java classes, once they are compiled.
  • Changed configuration files on the classpath, such as application.properties or application.yml.

By default, files in static/, public/, templates/, resources/, META-INF/resources/ and META-INF/maven/ do not trigger a restart. Those changes are picked up without one, because DevTools turns caching off.

4.3 See it work

Start this controller, then change the message and save:

HelloController.java
@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello from version 1"; // change to "version 2" and save
    }
}

The log shows the restart, using a thread named restartedMain:

Console
[  restartedMain] c.j.demo.DemoApplication : Started DemoApplication in 0.6 seconds

Call /hello again and you get the new message. If you see restartedMain in the log, DevTools restart is active.

5. Setting Up Your IDE

DevTools restarts only after your code is compiled. How that happens depends on your IDE:

IDEWhat to do
IntelliJ IDEAEnable Settings → Build, Execution, Deployment → Compiler → Build project automatically, and Settings → Advanced Settings → Allow auto-make to start even if developed application is currently running. Or press Build → Build Project (Ctrl+F9 / ⌘F9) after changes.
Eclipse / Spring ToolsWorks out of the box: saving a file compiles it automatically
VS CodeWorks out of the box with the Java extension, which compiles on save
Command lineRun ./mvnw spring-boot:run and recompile in another terminal with ./mvnw compile

If saving a file does not restart the application, the code is almost always not being compiled yet. Check the IDE setting first.

6. Restart vs Hot Reload

DevTools restarts the application. It does not swap code into the running JVM. These are different techniques:

TechniqueHow it worksKeeps state in memory?Tools
Automatic restartThrows away your classes and starts the application context againNoSpring Boot DevTools
Debugger hot swapReplaces method bodies in the running JVMYesAny IDE debugger, but only for changes inside existing methods
Advanced hot reloadReloads classes, including new methods and fields, without a restartYesJRebel (commercial), HotswapAgent with a special JDK

For most Spring Boot work, DevTools restart is the simplest and most reliable choice. Your application always starts from a clean state, exactly as it would in production.

7. Controlling What Triggers a Restart

Fine-tune restart behavior in application.properties:

application.properties
# Add exclusions to the defaults (static/, templates/ and so on remain excluded)
spring.devtools.restart.additional-exclude=reports/**,exports/**

# Watch an extra folder that is not on the classpath
spring.devtools.restart.additional-paths=../shared-config

# How often to look for changes, and how long to wait for more changes before restarting
spring.devtools.restart.poll-interval=1s
spring.devtools.restart.quiet-period=400ms
PropertyMeaning
spring.devtools.restart.enabledTurn automatic restart on or off (LiveReload and other features stay on)
spring.devtools.restart.excludeReplaces the default exclusion list
spring.devtools.restart.additional-excludeAdds to the default exclusion list; usually the one you want
spring.devtools.restart.additional-pathsExtra folders to watch for changes
spring.devtools.restart.poll-intervalTime between checks for changed files
spring.devtools.restart.quiet-periodWaits this long without further changes, so a burst of saves causes only one restart
spring.devtools.restart.trigger-fileRestart only when this specific file changes

7.1 Restart only when you say so

If your IDE compiles continuously, the application may restart more often than you like. A trigger file puts you in control: DevTools then restarts only when that one file changes:

application.properties
spring.devtools.restart.trigger-file=.reloadtrigger

Create an empty .reloadtrigger file on the classpath, for example in src/main/resources, and update it whenever you want a restart. Some IDEs can do this with one click.

7.2 Switching restart off completely

To disable restart regardless of any configuration file, set a system property before the application starts:

DemoApplication.java
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        System.setProperty("spring.devtools.restart.enabled", "false");
        SpringApplication.run(DemoApplication.class, args);
    }
}

8. LiveReload

DevTools starts a small LiveReload server on port 35729. When a browser is connected to it, the page refreshes automatically after a restart or after changes to HTML templates, CSS or JavaScript.

  1. Install a LiveReload extension in your browser.
  2. Start your application with DevTools.
  3. Open your page and switch the extension on for that tab.
  4. Change a template or stylesheet: the page refreshes by itself.

LiveReload is most useful for server-rendered pages, for example with Thymeleaf. If you build a separate front end with a tool like Vite or the Angular CLI, that tool usually has its own automatic refresh, and you can turn LiveReload off:

application.properties
spring.devtools.livereload.enabled=false

9. Development-Friendly Defaults

Some Spring Boot defaults are right for production but awkward during development. DevTools quietly changes a number of them while it is active:

Setting changed by DevToolsEffect during development
Template caching off (Thymeleaf, FreeMarker, Groovy templates, Mustache)Template edits appear on the next refresh, without a restart
Static resource caching offUpdated CSS, JavaScript and images are served immediately
Error details included (message, binding errors, stack trace)Error responses show what went wrong
H2 console enabledBrowse an in-memory H2 database at /h2-console
Persistent HTTP sessionsLogged-in sessions can survive a restart

These changes apply only while DevTools runs, so production keeps its safe, fast defaults. To switch them off and use your own settings, set spring.devtools.add-properties=false.

10. Global Settings for All Projects

Some DevTools settings are personal preferences, such as a trigger file or turning LiveReload off. Rather than adding them to every project, put them in one global file in your home folder:

~/.config/spring-boot/spring-boot-devtools.properties
spring.devtools.restart.trigger-file=.reloadtrigger
spring.devtools.livereload.enabled=false

These settings apply to every Spring Boot application you run on your machine that uses DevTools, and they never end up in a shared repository. A .yml or .yaml file in the same folder also works. Older versions used ~/.spring-boot-devtools.properties, which is still read when the newer folder does not exist.

11. Remote DevTools

DevTools can also update an application running on another machine, such as a development server, by sending your changed classes to it over HTTP. Both sides need setup:

pom.xml (remote application)
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <!-- keep DevTools inside the packaged JAR -->
        <excludeDevtools>false</excludeDevtools>
    </configuration>
</plugin>
application.properties (remote application)
spring.devtools.remote.secret=a-long-random-secret-value

On your own machine, run org.springframework.boot.devtools.RemoteSpringApplication from the IDE, with the remote URL as the program argument, for example https://dev.example.com. Changes you compile locally are then pushed to the remote application, which restarts.

Use this with great care. Anyone who knows the secret can change the code of the running application. Only enable it on trusted development servers, always over HTTPS, and never on production.

12. Keeping DevTools Out of Production

DevTools disables itself automatically in two ways:

  • It is not packaged. The Spring Boot Maven plugin leaves DevTools out of the final JAR by default, and Gradle’s developmentOnly configuration is never packaged.
  • It turns itself off when the application is started with java -jar as a fully packaged application, even if DevTools were somehow included.

You can confirm that it is gone from the JAR:

Terminal
./mvnw clean package
jar tf target/demo-0.0.1-SNAPSHOT.jar | grep devtools   # prints nothing: not packaged

Also check the production startup log: the main thread should be named main, not restartedMain.

13. Troubleshooting

ProblemLikely causeFix
Saving a file does nothingThe IDE is not compiling automaticallyEnable automatic build, or build manually (section 5)
Restarts happen constantlyA tool keeps writing files to the classpath, such as generated sources or logsExclude that folder with additional-exclude, or use a trigger file
Two restarts for one changeThe IDE saves several files a moment apartIncrease spring.devtools.restart.quiet-period
ClassCastException: X cannot be cast to XThe same class was loaded by both classloadersTell DevTools which JARs belong to the restart classloader (see FAQ)
Template changes do not appearA custom template setting re-enables cachingRemove cache=true settings from development properties
No restartedMain in the logDevTools is not on the classpath, or the app runs as a packaged JARCheck the dependency and run from the IDE or spring-boot:run

14. Best Practices

  • Add DevTools as optional/runtime in Maven or developmentOnly in Gradle, so it never reaches production.
  • Set up automatic compiling in your IDE, so restarts happen on save.
  • Use additional-exclude rather than exclude, to keep the sensible default exclusions.
  • Keep personal preferences in the global settings file, not in shared project files.
  • Use a trigger file if automatic restarts interrupt your flow.
  • Do not rely on in-memory state surviving restarts; use a database, even an embedded one, for test data.
  • Avoid Remote DevTools except on trusted development servers, and never in production.

15. Advantages and Limitations

AdvantagesLimitations
Much faster feedback after code changesRestart, not true hot reload: in-memory data is lost
No manual stop and startNeeds automatic compiling in some IDEs
Template and static changes show instantlyRare classloader issues with some libraries
Helpful error details and the H2 console during developmentLiveReload needs a browser extension
Safe by default: off in packaged production JARsRemote DevTools carries security risks

16. Summary

Spring Boot DevTools makes development faster with almost no setup. Add one dependency, set your IDE to compile automatically, and your application restarts within moments of every change, thanks to its two-classloader design. LiveReload refreshes the browser, development-friendly defaults turn off caching and show error details, and a global file keeps your personal preferences. DevTools stays out of production on its own; confirm it with a quick check of your packaged JAR.

17. Frequently Asked Questions (FAQ)

Q1. Will DevTools end up in my production JAR?

Not with the standard setup. The Spring Boot Maven plugin removes DevTools from the packaged JAR by default, and Gradle never packages the developmentOnly configuration.

Even if it were packaged, DevTools turns itself off when the application starts as a fully packaged JAR with java -jar. The only way to keep it active is to deliberately set excludeDevtools to false, which you should do only for Remote DevTools on a trusted server.

Q2. Why doesn’t my application restart when I save a file in IntelliJ IDEA?

DevTools watches compiled classes, and IntelliJ does not compile on save by default. Either build manually with Build → Build Project (Ctrl+F9 / ⌘F9), or turn on automatic building:

  1. Settings → Build, Execution, Deployment → Compiler: tick Build project automatically.
  2. Settings → Advanced Settings: tick Allow auto-make to start even if developed application is currently running.

After that, saving a change compiles it within a moment, and DevTools restarts the application.

Q3. Does a DevTools restart keep my data and logged-in users?

Partly:

  • In-memory data is lost. Maps, lists, caches and anything else held in your beans start empty again, because the application context is recreated.
  • HTTP sessions can survive. DevTools enables persistent sessions, so a logged-in user often stays logged in. The objects stored in the session must be Serializable.
  • Database data is kept in a real database. An in-memory H2 database is lost, unless you load sample data at startup.

A data.sql file or a small CommandLineRunner that inserts sample data makes restarts painless.

Q4. How do I fix “ClassCastException: X cannot be cast to X” with DevTools?

This strange-looking error means one class was loaded twice, once by each of DevTools’ two classloaders, so Java sees two different types with the same name. It usually involves a library from your own company, such as a shared module of entity classes, opened in the IDE as a project.

Tell DevTools to load that library with the restart classloader too. Create this file in your application:

# src/main/resources/META-INF/spring-devtools.properties
restart.include.shared-model=/shared-model-[\\w\\d-\\.]+\\.jar

The value is a pattern matching the JAR’s file name. There is also restart.exclude.* for the opposite case.

Q5. Is DevTools active when I run my tests?

Restart is switched off when DevTools detects a test framework such as JUnit, so tests are never interrupted by a restart.

However, the development-friendly default properties, such as disabled caching, may still apply when DevTools is on the test classpath. If a test depends on production-like settings, set them explicitly in the test properties, or set spring.devtools.add-properties=false.

Q6. Do template changes cause a restart?

No. Files under templates/, static/ and public/ are excluded from restart on purpose. They do not need one: DevTools turns off template and resource caching, so the next page load simply reads the new file.

This makes front-end work especially quick. Edit a Thymeleaf page or a stylesheet, refresh the browser, or let LiveReload do it, and the change is there, with no restart at all.

Q7. Do I need to restart manually after changing dependencies in pom.xml?

Yes. DevTools only reloads your own classes; library JARs live in the base classloader, which is kept across restarts. A new or upgraded dependency therefore needs a full restart:

  1. Reload the Maven or Gradle project in your IDE.
  2. Stop the application completely.
  3. Start it again.

The same applies to changes in JVM options and environment variables.

Q8. What do the poll interval and quiet period mean?
SettingDefaultMeaning
poll-interval1sHow often DevTools checks the classpath for changed files
quiet-period400msHow long there must be no further changes before a restart begins

Compiling often writes many files one after another. The quiet period waits for that burst to finish, so you get one restart instead of several. If you still see double restarts, increase it:

spring.devtools.restart.poll-interval=2s
spring.devtools.restart.quiet-period=1s

The poll interval must always be longer than the quiet period.

Q9. What is the “condition evaluation delta” in the log after a restart?

After each restart, DevTools logs which auto-configurations changed compared with the previous start. For example, after you add a database setting, it shows that the DataSource auto-configuration now applies.

This is a quick way to see the effect of a configuration change. If it clutters your log, switch it off:

spring.devtools.restart.log-condition-evaluation-delta=false
Q10. How do I pause automatic restarts without removing DevTools?

Choose the option that fits:

  • For one project: spring.devtools.restart.enabled=false in application.properties. LiveReload and the development defaults keep working.
  • For one run: start with -Dspring.devtools.restart.enabled=false as a JVM option in your IDE’s run configuration.
  • Restart only on demand: configure a trigger file (section 7.1).
Q11. Does DevTools work inside a Docker container?

Not out of the box, and usually it is not worth it. DevTools needs compiled classes on the container’s classpath to change, and a typical container runs a packaged JAR, in which DevTools is switched off.

Common, simpler approaches:

  • Run the application on your machine with DevTools, and run only the databases and other services in Docker, for example with Docker Compose.
  • Use Spring Boot’s Docker Compose support (spring-boot-docker-compose), which starts those services automatically when the app starts.

Remote DevTools can push changes into a container, but it adds setup and security concerns.

Q12. What is the difference between DevTools and Spring Boot’s Docker Compose support?
DevToolsDocker Compose support
Modulespring-boot-devtoolsspring-boot-docker-compose
Helps withYour own code: fast restarts and LiveReloadExternal services: starting databases, brokers and caches
HowWatches the classpath and restartsRuns docker compose up and connects the app to the services

They solve different problems and work well together: Docker Compose support starts PostgreSQL for you, and DevTools restarts your code as you change it.

Q13. Is Remote DevTools safe to use?

Only in limited conditions. Remote DevTools lets anyone who knows the secret replace the code of the running application. That is very powerful and, therefore, dangerous.

  • Use it only on development servers that you trust and control.
  • Always use HTTPS, so the secret and your classes are not sent in plain text.
  • Use a long, random secret, and do not commit it to source control.
  • Never enable it on production or on anything reachable from the internet.
Q14. Does DevTools work with Spring WebFlux and other non-MVC applications?

Yes. Automatic restart works for any Spring Boot application, whether it uses Spring MVC, WebFlux, or has no web layer at all, such as a command-line tool or a message consumer.

LiveReload and the template-related defaults only matter for applications that serve web pages. For other applications, DevTools is still useful just for the fast restart.

Q15. Why does my application keep restarting in a loop?

Something keeps writing files into a watched folder, and each write triggers another restart. Common causes:

  • The application itself writes files, such as logs, uploads or exports, into src/main/resources or the build output folder.
  • A code generator, for example for OpenAPI clients, runs on every build and rewrites its output.
  • A front-end build writes into the classpath continuously.

Write runtime files outside the project, or exclude their folder:

spring.devtools.restart.additional-exclude=uploads/**,generated/**
Q16. Does DevTools slow down my application while I develop?

Only slightly. DevTools checks for file changes about once a second, which costs very little. The development defaults, such as disabled caching, make each page request a little slower, because templates and files are read again every time.

That trade-off is intended for development. Never judge your application’s real speed with DevTools active; measure performance with a packaged JAR, as production runs it.

Q17. Can I use LiveReload without installing a browser extension?

The classic way requires a LiveReload extension, and such extensions are not available or maintained for every browser. Alternatives:

  • Many IDEs, such as IntelliJ IDEA Ultimate, can refresh the browser on their own when files change.
  • Front-end dev servers such as Vite or webpack have built-in instant refresh, which suits single-page applications better.
  • Simply press refresh: thanks to disabled caching, template and CSS changes are visible immediately.

If you do not use LiveReload, turn it off with spring.devtools.livereload.enabled=false to free port 35729.

Q18. Is DevTools the same as “hot reload” in other frameworks?

Not exactly. Many front-end frameworks swap changed code into the running page while keeping its state. DevTools instead restarts the Spring application context quickly, so in-memory state is reset.

In practice the result feels similar: you save, and the change is live a moment later. The restart approach has an advantage, too: every restart begins from a clean state, so you never debug a confusing mix of old and new code.

Q19. Should every developer on the team use the same DevTools settings?

Split them into two groups:

Kind of settingWhere to put itExample
Needed by the projectapplication.properties (shared)additional-exclude for a generated folder
Personal preferenceGlobal file in your home folderTrigger file, LiveReload off

This way, the project works well for everyone, while each developer keeps their preferred workflow without changing shared files.

Q20. How can I tell whether DevTools is really active?

Three quick checks:

  1. The thread name. Startup log lines show restartedMain instead of main.
  2. The LiveReload message. The log mentions that the LiveReload server is running on port 35729, unless you turned it off.
  3. A quick test. Change a string in a controller, compile, and see whether the application restarts by itself.

If none of these happen, check that the dependency is present and that you run the application from the IDE or with spring-boot:run, not from a packaged JAR.