1. Introduction

Thymeleaf is a template engine that we can use for our Spring Boot applications. As with many things, Spring Boot provides a default location where it expects to find our templates.

In this short tutorial, we will look at how we can change the template location. After we do that, we’ll learn how to have multiple locations.

2. Setup

To use Thymeleaf, we need to add the appropriate Spring Boot starter to our pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    <versionId>3.1.5</versionId>
</dependency>

3. Changing the Default Location

By default, Spring Boot looks for our templates in src/main/resources/templates. We can put our templates there and organize them in sub-directories and have no issues.

Now, let’s imagine that we have a requirement that all our templates reside in a directory called templates-2.

Let’s create a template for saying hello and put it in src/main/resources/templates-2:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Enums in Thymeleaf</title>
</head>
<body>
    <h2>Hello from 'templates/templates-2'</h2>
</body>
</html>

We’ll also need a controller:

@GetMapping("/hello")
public String sayHello() {
    return "hello";
}

With that basic setup out of the way, let’s configure Spring Boot to use our templates-2 directory by overriding a property in application.properties:

spring.thymeleaf.prefix=classpath:/templates-2/

Now, when we call our HelloController, we’ll see our greeting from hello.html.

4. Using Multiple Locations

Now that we’ve learned how to change the default location let’s see how we can use multiple template locations.

To do this, let’s create a ClassLoaderTemplateResolver bean:

@Bean
public ClassLoaderTemplateResolver secondaryTemplateResolver() {
    ClassLoaderTemplateResolver secondaryTemplateResolver = new ClassLoaderTemplateResolver();
    secondaryTemplateResolver.setPrefix("templates-2/");
    secondaryTemplateResolver.setSuffix(".html");
    secondaryTemplateResolver.setTemplateMode(TemplateMode.HTML);
    secondaryTemplateResolver.setCharacterEncoding("UTF-8");
    secondaryTemplateResolver.setOrder(1);
    secondaryTemplateResolver.setCheckExistence(true);
        
    return secondaryTemplateResolver;
}

In our custom bean, we set our prefix to the secondary template directory we use: templates-2. We also set the CheckExistance flag to true. This is the key to allowing the resolvers to operate in a chain.

With this configured, our application can use templates from the default main/resources/templates directory and main/resources/templates-2.

5. Errors

When we’re working with Thymeleaf, we might see this error:

Error resolving template [hello], template might not exist or might not be accessible
  by any of the configured Template Resolvers

We see this message when Thymeleaf cannot locate the template for some reason. Let’s look at some possible reasons for this and how to fix them.

5.1. Typo in the Controller

We can often see this error due to a simple typo. The first thing to check is that our file name minus the extension and the template we’re asking for in our controller, match exactly. If we’re using subdirectories, we must also ensure that those are correct.

Additionally, the problem can be an issue with certain operating systems. Windows is not case-sensitive, but other operating systems are. We should look into this if everything is working fine, say, on our local Windows machine, but not once we’ve deployed.

5.2. Including the File Extension in the Controller

Since our files typically have an extension, it can be natural to include them when we return our template path in the controller. Thymeleaf automatically appends the suffix, so we should avoid supplying it.

5.3. Not Using the Default Location

We’ll also see this error if we place our templates somewhere other than src/main/resources/templates. If we want to use a different location, we need to set the spring.thymeleaf.prefix property or create our own ClassLoaderTemplateResolver bean to handle multiple locations.

6. Conclusion

In this quick tutorial, we learned about Thymeleaf template locations. First, we saw how to change the default location by setting a property. Then we built on that by creating our own ClassLoaderTemplateResolver to use multiple locations.

We wrapped up with a discussion of the error we’ll see when Thymeleaf can’t find our templates and how to solve it.

As always, the example code can be found on GitHub.