Taming Thymeleaf update for Spring Boot 3

Posted at — Mar 31, 2023
Taming Thymeleaf cover
Interested in learning more about Thymeleaf? Check out my book Taming Thymeleaf. The book combines all of my Thymeleaf knowledge into an easy to follow step-by-step guide.

My book Taming Thymeleaf has just been updated on leanpub for Spring Boot 3. This blog post will walk you through the most important changes if you want to upgrade to Spring Boot 3 from Spring Boot 2 if you used the previous version of the book.

To view the changes I did on the demo project, check out this commit on GitHub. You can also compare the changes between versions.

Spring Boot updates

  • Be sure you are already on Java 17. If not, first update to Spring Boot 2.7.x and Java 17.

  • Update the Spring Boot version in the pom.xml to 3.0.4

  • Update JPearl to 2.0.0.

  • Update Testcontainers to 1.17.6.

  • Update testcontainers-cypress to 1.8.0.

I also updated to Maven 3.8.7, altough that is not strictly needed.

Thymeleaf updates

  • Remove gulpfile.js as the live reload system no longer needs Gulp when it is generated via ttcli.

  • Update package.json. Take a look at GitHub to see the exact changes, or generate a new one using the ttcli tool.

  • Update frontend-maven-plugin to 1.21.1.

  • Update frontend-maven-plugin.nodeVersion to v18.15.0.

  • Update frontend-maven-plugin.npmVersion to 9.5.0.

  • Add AlpineJs, Duet datepicker and Luxon as webjar dependencies:

    <!-- Web dependencies -->
  • Update the postcss.config.js to:

    const postcssConfig = {
        plugins: [require('autoprefixer'),
    // If we are in production mode, then add cssnano
    if (process.env.NODE_ENV === 'production') {
                // use the safe preset so that it doesn't
                // mutate or remove code from our css
                preset: 'default',
    module.exports = postcssConfig;
  • There is now a warning in Thymeleaf if you use th:replace like this:

    <div th:replace="fragments/forms :: fielderrors"></div>

    Change it to use the ~{..} syntax to avoid the warning:

    <div th:replace="~{fragments/forms :: fielderrors}"></div>
  • AlpineJS is now loaded via webjars. Replace:

    <script src="https://unpkg.com/alpinejs@3.7.0/dist/cdn.min.js" defer></script>


    <script type="text/javascript" th:src="@{/webjars/alpinejs/dist/cdn.min.js}" defer>
  • Duet Date Picker and Luxon are also loaded via webjars. Replace:

    <script type="module" src="https://cdn.jsdelivr.net/npm/@duetds/date-picker@1.1.0/dist/duet/duet.esm.js"></script>
        <script nomodule src="https://cdn.jsdelivr.net/npm/@duetds/date-picker@1.0.1/dist/duet/duet.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/luxon@1.25.0/build/global/luxon.min.js"></script>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@duetds/date-picker@1.1.0/dist/duet/themes/default.css"/>


    <script type="module" th:src="@{/webjars/duetds__date-picker/dist/duet/duet.esm.js}"></script>
        <script nomodule th:src="@{/webjars/duetds__date-picker/dist/duet/duet.js}"></script>
        <script th:src="@{/webjars/luxon/build/global/luxon.min.js}"></script>
        <link rel="stylesheet" th:href="@{/webjars/duetds__date-picker/dist/duet/themes/default.css}"/>

Java code updates

  • Replace imports of org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver with org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver

  • Rework the WebSecurityConfiguration to no longer use WebSecurityConfigurerAdapter. See Spring Security without the WebSecurityConfigurerAdapter for more info.

  • Replace all javax. imports with jakarta. imports.

  • PagingAndSortingRepository no longer extends from CrudRepository, so you might have to add this to your Repository interface yourself.

Cypress updates

Update the src/test/e2e/package.json for the new Cypress:

  "name": "taming-thymeleaf-tests",
  "devDependencies": {
    "cypress": "^12.9.0",
    "cypress-multi-reporters": "^1.6.3",
    "mocha": "^10.2.0",
    "mochawesome": "^7.1.3"

In Cypress 12, the cypress.json configuration file is no longer supported. Replace it with this cypress.config.js:

const {defineConfig} = require('cypress');

module.exports = defineConfig({
    e2e: {
        'baseUrl': 'http://localhost:8080',
        'viewportWidth': 1100,
        'viewportHeight': 800,
        "reporter": "cypress-multi-reporters",
        "reporterOptions": {
            "configFile": "reporter-config.json"
        setupNodeEvents(on, config) {
            // implement node event listeners here

The spec files now must be called foo.cy.js instead of foo.spec.js and they should be in the e2e directory instead of the integration directory. Be sure to rename and move them, otherwise Cypress will no longer find them.


Applying all that should make your application work smoothly on Spring Boot 3.

If you have any questions or remarks, feel free to post a comment at GitHub discussions.

If you want to be notified in the future about new articles, as well as other interesting things I'm working on, join my mailing list!
I send emails quite infrequently, and will never share your email address with anyone else.