Skip to content

JTE vs Thymeleaf: Which Spring Boot Template Engine?

Java Code

After eight years building Spring Boot REST APIs, I realized I needed to add a user interface to my internal tools. The thought of learning React, TypeScript, and Node.js felt overwhelming. Like many backend developers, I just wanted something simple that works with what I already know.

That’s when I discovered the template engine dilemma: JTE or Thymeleaf? I initially chose JTE because it seemed modern and avoided JavaScript complexity. But now I’m second-guessing that decision after hearing what the community has to say.

The Backend Developer’s Dilemma

When you’re a backend developer who wants to add UI without diving deep into frontend frameworks, you face three options:

Options for adding UI to Spring Boot
1. Learn modern frontend frameworks (React/Angular/Vue)
- Steep learning curve
- Requires TypeScript and Node.js knowledge
- Build complexity increases
2. Use traditional template engines
- Evaluate maturity and ecosystem
- Consider Spring Boot integration
- Trade simplicity for limited interactivity
3. Abandon server-side rendering entirely
- SPA architecture complexity
- API state management challenges
- Requires frontend expertise anyway

I chose option 2, but then had to pick between JTE and Thymeleaf.

JTE: The Modern Contender

JTE appealed to me because of its compiled templates and natural syntax. It integrates with Spring Boot via the jte-spring-boot-starter and doesn’t require any frontend build tools.

pom.xml for JTE dependency
<dependency>
<groupId>gg.jte</groupId>
<artifactId>jte-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>

The syntax feels intuitive for Java developers:

src/main/jte/users/list.jte
@import gg.jte.Content
@param List&lt;User&gt; users
<!DOCTYPE html>
<html>
<head>
<title>User List</title>
</head>
<body>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@for(user : users) {
<tr>
<td>${user.name}</td>
<td>${user.email}</td>
<td>
<button onclick="loadEditForm(${user.id})">Edit</button>
</td>
</tr>
}
</tbody>
</table>
</body>
</html>

The performance from compiled templates is excellent. But here’s the problem: the ecosystem is still young.

Thymeleaf: The Mature Choice

Thymeleaf has been around since 2011. That matters because a mature ecosystem means:

Thymeleaf ecosystem advantages
- Extensive documentation and tutorials
- Strong IDE support in IntelliJ and Eclipse
- Large community and Stack Overflow presence
- Spring-specific dialect with deep integration
- Third-party libraries and extensions
- Long-term support and stability

Adding Thymeleaf to your Spring Boot app is straightforward:

pom.xml for Thymeleaf dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Here’s a template that shows the natural template approach:

resources/templates/list.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>User List</title>
<script src="https://unpkg.com/htmx.org"></script>
</head>
<body>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users}">
<td th:text="${user.name}"></td>
<td th:text="${user.email}"></td>
<td>
<button hx-get="/users/${user.id}/edit"
hx-target="#modal"
hx-swap="innerHTML">
Edit
</button>
</td>
</tr>
</tbody>
</table>
<div id="modal"></div>
</body>
</html>
UserController.java
@Controller
@RequestMapping("/users")
public class UserController {
@GetMapping
public String list(Model model) {
model.addAttribute("users", userService.findAll());
return "list";
}
@GetMapping("/{id}/edit")
public String editForm(@PathVariable Long id, Model model) {
model.addAttribute("user", userService.findById(id));
return "fragments/user-form :: form";
}
}

The HTMX Game Changer

The key insight from the community is this: Thymeleaf alone can feel dated, but Thymeleaf + HTMX provides modern interactivity without frontend framework complexity.

Community consensus from Reddit
- smutje187: "Thymeleaf plus htmx is also great"
- nozomashikunai_keiro: "+1 for Thymeleaf/HTMX. Very very nice to work with those."
- OV106: "The ecosystem is just not there for JTE."

HTMX lets you add dynamic behavior with simple attributes. No JavaScript framework needed. The button in the Thymeleaf example above uses HTMX to load an edit form into a modal without page refresh.

Common Mistakes to Avoid

1. Choosing JTE for the wrong reasons

Don’t pick JTE just to avoid JavaScript. The ecosystem limitation is real. As one developer put it: “JTE has been trying to be what past frameworks were, like Java Server Faces or Google Web Toolkit, the ecosystem is just not there.”

Consider:

  • Team onboarding ease
  • Long-term maintenance
  • Available third-party integrations

2. Not exploring HTMX with Thymeleaf

Thymeleaf templates without HTMX feel static. Add HTMX, and you get modern interactivity with minimal JavaScript. This combo is highly recommended.

3. Over-engineering with Angular/React

For simple admin panels, internal tools, or CRUD apps, a full SPA framework is overkill. You’ll waste time learning complex frontend tooling when server-side rendering is perfectly adequate.

My Recommendation

After researching and hearing from the community, here’s where I stand:

Choose Thymeleaf if you want:

Thymeleaf strengths
- Mature, battle-tested solution
- Extensive documentation and community support
- Strong IDE integration
- Easy onboarding for new team members
- HTMX integration for modern interactivity

Choose JTE if you prefer:

JTE strengths
- Compiled template performance
- Simpler, more intuitive syntax
- Complete control over template rendering
- A newer, modern approach to templating

Start with Thymeleaf + HTMX. This combination provides the best of both worlds: server-side rendering with modern interactivity, backed by a mature ecosystem and strong community support.

The Reddit consensus is clear: the ecosystem advantage of Thymeleaf makes it the pragmatic choice for most Spring Boot applications, especially when enhanced with HTMX for dynamic functionality.

I’m now reconsidering my JTE choice for new projects. The ecosystem matters more than I initially thought, and Thymeleaf’s maturity provides peace of mind for long-term maintenance.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments