Spring Boot Live Reload Templates without Restart

Can I just start by exclaiming? ZOMG why was this so difficult to figure out?!?!? I'm working on a new Spring Boot project using Thymeleaf templates. The Java code is actually pretty minimal but there is quite a bit of styling to be done and template work. I wanted to be able to change an HTML file and have LiveReload trigger the browser refresh but the default behavior is for the app to restart as well. After much trial and error I nailed down the right combination of configuration options to make this work.

First, you'll want to move your templates out of the resource directory all together. I just created a new templates directory under src. Reason is, DevTools watches that classpath location for changes, which will trigger an app restart. Plus, I've never been a big fan of templates being wrapped up in JAR/WAR files anyway. Then, update your application config (.properties or .yml) to specify the new location.

spring:  
  resources:
    static-locations: file:./src/static/
  thymeleaf:
    cache: false
    prefix: file:./src/templates/
  devtools:
    restart:
      enabled: true
    livereload:
      enabled: true

(for the file: paths to work, you'll need to setup your working directory in your IDE's run configuration. Otherwise, use the absolute path. And it's probably a good idea to have a dev profile different from what you want to do in production)

Now for the confusing part. You need to tell devtools.restart about the additional paths to watch.

spring:  
  resources:
    static-locations: file:./src/static/
  thymeleaf:
    cache: false
    prefix: file:./src/templates/
  devtools:
    restart:
      enabled: true
      additional-paths: ./src/templates/
    livereload:
      enabled: true

But wait, this tells restart to restart when something changes in that path. I thought we wanted to disable restarts but only allow reload? Well, that's the confusing part. In order to trigger the reload to fire, it has to be in restart.additional-paths but then we need to exclude it from the restart with restart.additional-exclude.

spring:  
  resources:
    static-locations: file:./src/static/
  thymeleaf:
    cache: false
    prefix: file:./src/templates/
  devtools:
    restart:
      enabled: true
      additional-exclude: "**/*.js,**/*.css,**/*.html"
      additional-paths: ./src/templates/
    livereload:
      enabled: true

So I don't know. It's weird. It's confusing. It's undocumented that it works this way. But hey, it works! I guess I should stop complaining and just go submit a PR to the Spring Documentation. After all, it is open source. I love you Spring!