📖 Introduction: Common Misconceptions
In today’s modern web ecosystem, we encounter such sharp boundaries that a large number of new generation developers believe that backend and frontend architectures should be completely isolated. At the heart of this perception often lies the following simplification:
❌ Common Misconception: “Spring Boot is simply a REST API server that returns JSON data; the interface must be a React/Vue application hosted on an external server (Vercel, Netlify, AWS S3, etc.).”
This assumption is completely wrong! Spring Boot carries an embedded Apache Tomcat server at its heart. This integration means it’s not just a lightweight data management service, but also a massive web server capable of handling all application layers (Full-Stack) under one roof, avoiding microservice complexity, and creating easy-to-deploy, highly performant monolithic structures.
This article will explore four different methods, along with architectural and practical code structures, for combining user interface technologies directly into a single .jar file using the embedded power of Spring Boot.
🏗️ The Foundation of the Architecture: Single JAR Distribution and its Advantages
Bundling everything into a single Spring Boot project (Single JAR Deployment) has unique advantages for independent developers (Indie Hackers) and enterprise monolith projects:
✅ Zero CORS Problems
Since the frontend and backend communicate over the same port and domain (localhost:8080), the common browser restrictions on Cross-Origin Resource Sharing are completely eliminated.
💰 Minimal Server Cost
There’s no need for a separate Node.js or static file server. A single.jar file running inside a single Linux server or Docker container can bring the entire website up and running.
🔄 Easy CI/CD
With just one Maven or Gradle build process, both the user interface is compiled and the server package is ready.
📁 Embedded Tomcat File Presentation Structure
(1) Spring Boot + Thymeleaf / JSP
📄 Traditional Server-Side Templating (SSR)
Server-side rendering allows data to be embedded into HTML before it even reaches the client. It offers significant security and SEO advantages.
🔌 Thymeleaf Integration
In the modern Spring ecosystem, Thymeleaf is recommended as the default templating engine instead of JSP. It fully preserves the valid HTML5 structure.
Maven Dependency (pom.xml)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Controller Layer
@Controller
public class HomeController {
@GetMapping("/hello")
public String sayHelo(Model model) {
model.addAttribute("message", "Spring Boot and Thymeleaf team up!");
return "home"; // searchs src/main/resources/templates/home.html file
}
}
Template File (src/main/resources/templates/home.html)
<html xmlns:th="http://www.thymeleaf.org">
<body>
<h1 th:text="${message}">Default Text</h1>
</body>
</html>
⚠️ JSP/War Note:
If you prefer using old-school JSP, you should package your Spring Boot project as a .war file instead of a standart .jar file and add the tomcat-embed-jasper dependency. However, Thymeleaf is much more flexible for modern builds.
(2) Fully Integrated React Applications with Spring Boot + Vaadin
Vaadin (v22+) enables Java developers to build modern, reactive single-page web applications (SPAs) entirely with Java objects, without writing a single line of JavaScript or CSS.
In the background, Vaadin transforms your Java code into optimized React components and automatically manages client-server communication via WebSocket (Atmosphere framework) or optimized XHR.
for pom.xml
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-spring-boot-starter</artifactId>
</dependency>
Interface Development with Java
@Route("") // Runs in the root directory of application (/)
public class MainView extends VerticalLayout {
public MainView() {
TextField adInput = new TextField("Name:");
Button buton = new Button("Send");
buton.addClickListener(click -> {
Notification.show("Hello, " + adInput.getValue() +
"! This is a React WebApp.");
});
add(adInput, buton);
}
}
Vaadin automatically installs a Node.js integration when you compile the project, prepares the necessary React components in the background, and serves them to the browser via the embedded Tomcat. It’s perfect for those who want to leverage the power of React without venturing into the world of JavaScript.
(3) Spring Boot + JSF (PrimeFaces / BootsFaces) Architecture
Especially in the modernization of enterprise and data-intensive legacy systems, JSF (JavaServer Faces) remains very powerful with its rich component libraries. It’s possible to achieve modern designs by using PrimeFaces and BootsFaces components together under the Spring Boot framework.
In the Spring configuration, we need to manually register the JSF FacesServlet component in the embedded Tomcat.
Servlet Registry Configuration
@Configuration
public class JsfConfig {
@Bean
public ServletRegistrationBean<FacesServlet> facesServletRegistration() {
ServletRegistrationBean<FacesServlet> registration =
new ServletRegistrationBean<>(new FacesServlet(), "*.xhtml");
registration.setLoadOnStartup(1);
return registration;
}
}
*PrimeFaces and BootsFaces hybrid XHTML src/main/webapp/index.xhtml
*
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:b="http://bootsfaces.net/ui">
<h:head>
<title>JSF and Spring Boot</title>
</h:head>
<h:body>
<b:container> <!-- BootsFaces Grid -->
<b:jumbotron>
<h2>Enterprise Solution: JSF & Spring Boot</h2>
</b:jumbotron>
<h:form>
<!-- PrimeFaces Advanced Component -->
<p:colorPicker value="#{jsfBean.colorPicker}"/>
<p:commandButton value="Save" action="#{jsfBean.save}"/>
</h:form>
</b:container>
</h:body>
</html>
This architecture allows you to run your enterprise backend services with Spring dependency injection (DI), while deploying the frontend with thousands of JSF’s ready-to-use enterprise components.
(4) Cracking a Pure React Application into an Embedded Tomcat Folder
🎯 The Indie Hacker Way
If you have an independent frontend team or want to serve an external React repository within a single JAR, this is the most aggressive and performant approach. The process can be fully automated.
📋 Roadmap and Automation
- In your React project, go to the terminal and run the npm run build command (the same applies if you’re using Vite).
- You copy all the files (index.html, assets/ folder etc.) under thedist/ veya build/ folder that is created as a result of the compilation.
- You paste these files into the src/main/resources/static/ directory of your Spring Boot project.
Automation with Maven Plugin
Instead of doing this manually each time, you can automate it by linking it to the Maven build process using the frontend-maven-plugin :
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.12.1</version>
<!--
With configuration, the `npm install` and `npm run build` steps
run automatically when the JAR package is being created.
-->
</plugin>
🚨 Critical Tip: Server Routing for React Router
React is a single-page application (SPA). If a user types domain.com/dashboard directly into the browser, Tomcat will search for a physical file in that directory and return a 404 error if it cannot find one.
To prevent this, you should write a Controller that redirects all unknown requests to React’s index.html file:
@Controller
public class SpaController {
@RequestMapping("/{path:[^\\.]*}")
public String redirectAll() {
return "forward:/"; // It passes the request to the client-side router (React Router).
}
}
🎯 Conclusion: Which Method, When?
As you can see, Spring Boot can support a huge ecosystem on its own, thanks to the embedded Apache Tomcat server. Choosing the right architecture depends on your project’s needs:
Before you start browsing server after server on your next project, don’t forget to push the limits of your embedded Tomcat! 🎯




Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.