Note: The following is an excerpt from Quarkus in Action by Martin Štefanko and Jan Martiška (Manning Publications, January 2025). Download the full e-book at no cost and learn how to build Java applications using Quarkus from the ground up.
With a vast ecosystem of libraries, frameworks, standards, runtimes, and experienced developers, Java is a great choice for building modern, robust, and scalable software. In today’s data-oriented, cloud-first, cost-sensitive world, Java is also sometimes viewed as mature, slow, and resource-intensive. Quarkus changes this perception, offering a fast, lightweight, and flexible Java framework perfect for modern enterprise applications.
Quarkus combines popular libraries, Java standards, and best practices with an innovative approach to building and running applications, delivering both great user experience and developer productivity. Its build processing-oriented architecture results in smaller and faster runnable artifacts, perfect for contemporary designs like microservices and serverless as well as more traditional monolithic applications. It’s also great for specialized use cases like CLI apps, edge, GitHub actions, and Kubernetes operators.
Why Quarkus?
It’s natural to ask, “Why do I need to learn a new framework when we already have framework X?” Java frameworks like Spring have been around for years and have extensive public documentation, problem solutions, and user stories, as well as massive legacy codebases. When these frameworks were designed—in some cases, 20+ years ago—the Java world was very different.
Java was originally designed for big, long-running applications, which created a perception that it didn’t fit particularly well into modern computing environments. With the move to the cloud environments, application startup times and memory/CPU utilization became the prominent application metrics. Long starts and the high memory use of Java applications are no longer acceptable since such processing translates directly into cloud costs.
Quarkus was created to address these challenges. It defines a very lightweight framework that splits the application processing into the build-time and runtime phases. Any Java stack needs to do a lot of processing once the application starts—for example, reading and processing the application’s code, annotations, configuration, injection points (inversion of control), or generating dynamic code to initialize the application within the framework properly. And all of this processing repeats with every application start.
Quarkus moves as much processing as possible to the build-time phase (application build/packaging) to save resources at runtime. The packaged application carries only the results of these initial framework operations, which makes it not only faster to start since they don’t need to be executed at startup but also smaller in size because any code that is needed only in this initialization phase is never included in the final packaged artifact.
While performance benefits are very important, Quarkus also puts enormous effort into the developer experience when using the framework. It provides the Dev mode, which is a continuous execution of the Quarkus application, allowing live reloads of code and configuration changes. By just saving our changes in the editor and invoking the application, Quarkus dynamically applies those changes so we can see the results of our modifications in mere milliseconds. The development flow doesn’t need to stop to recompile and rerun the application, which closes the reevaluation loop in a continuous experience similar to scripting languages while we still work with the Java virtual machine (JVM). Dev mode bundles a lot of productivity boosting features that we dive into in this book.
Quarkus also exposes all these features for integrations, which makes it very popular among library developers too. With its over 700 extensions (pluggable pieces of functionalities) that integrate different popular libraries (e.g., Hibernate, Jackson, or LangChain4j), Quarkus proves that it stands out as a framework where the Java ecosystem wants to be.
Building the Acme Car Rental application using Quarkus
Throughout this book, we build a real-life application called Acme Car Rental. Most chapters will contribute some parts of the functionality, bringing everything together by the end. An application like car rental is realistic and broad enough to cover all the different technologies explained in this book. And it is a change from the to-do apps, blogs, and shops, which software stacks often use for their examples. It also lends itself to being architected using microservices. Microservice architecture is not a panacea, but it simplifies the teaching process as it cleanly separates different parts of the system.
You can find the code of the Acme Car Rental application at https://github.com/xstefank/quarkus-in-action. The repository subdivides the content into directories per chapter. Each directory contains subdirectories for the individual sections of the respective chapter that contain the final code after the particular section. The final version of the Acme Car Rental is provided in the acme-car-rental
root directory. If you have any problems, you always know where to look. You might also analyze the commit history, where you can see the respective code differences. We wanted to make this process as easy to consume as possible, so we also provide links to the relevant commits for each section right next to the particular section directory as shown in Figure 1.4. Each section directory has the commit diff links right next to it.

The provided code is excellent reference material. However, we chose to write this book so that you, the reader, can follow the development of the car rental system with us. Coding along with us isn’t required, but it can give you a very different experience. You may decide for yourself what your preferred practice is.
Use cases
To get an idea of the car rental application’s essential features, let’s evaluate the primary use cases that cover user management, billing, fleet management, and integration areas. It is important to understand the problems we are solving before diving into the actual solutions.
The car rental system requirements include an interface that employees can use to look up inventory and perform bookings. A modern interface must also expose this functionality to its customers via the web or mobile so that customers can browse, book, and pay for cars. Figure 1.5 visually represents the interface.

By analyzing how the customer utilizes the system, we can differentiate two use cases: user management and reservation making. User management relates to user login and register options provided by the Users service. This service acts as the user entry API that separates the rest of the services. Making the reservation is a more complicated process for which the customers need to log into the system. The Reservation service then provides cars received from the Inventory service filtered to only the available cars for the customer-selected time period. If the user decides to make the reservation, the Reservation service calls the Billing service to proceed with the payment.
What about employees? What is their interaction with the system now that most of the functionality is passed directly to the customers? Figure 1.6 provides a visual representation of the employee use cases and how they tie into the core system services.

Since renting a car requires interaction with an employee to verify the validity of the reservation, employees must have access to the system. An employee also performs other tasks, such as fleet management. Employees can register and remove vehicles through the Inventory service. They can also perform bookings, a multistep process that involves looking up the reservation, starting the rental in the Rental service, and paying through the Billing service.
The Acme Car Rental system is relatively simple on purpose. It represents an adequate complexity problem to solve, providing real-world examples of what developers may come across. We want to focus on explaining the Quarkus features without the need to provide genuine business value. However, we surely don’t mean that such a system wouldn’t make it in the real world.
Architecture
The previous section identified core actors, use cases, and potential services. If we are to embrace the microservices architecture, we compose the car rental system as a set of standalone applications. Each application represents an independent service and uses a decentralized data store. Services communicate using multiple channels, including REST, GraphQL, gRPC, RabbitMQ, and Kafka. Figure 1.7 shows how the services communicate with each other.

Real-life applications usually limit themselves to just a couple of different communication technologies, depending on their needs. However, we designed the car rental application for teaching purposes, and thus, it does not have such limits. It covers as many communication technologies as possible. The same applies to database technologies. Each service utilizes different data store, ranging from traditional relational to NoSQL (non-SQL) databases.
Since microservices systems rarely consist of only business services, our car rental also contains a few third-party services (not demonstrated in Figure 1.7) that provide some functionality for the whole system. Apparent examples would be the Kafka and RabbitMQ brokers that will propagate the messages between our services. But our car rental system also includes other services—for instance, the metrics registry (Prometheus) or the traces collector (Jaeger) integrated with the business microservices to collect their metrics or call traces, respectively.
We need to point out the Inventory CLI application at the bottom part of the architecture diagram. It represents a standalone command line Quarkus application employees can use to group operations over cars in the Inventory service. All other services composed together as Quarkus microservices are expected to run simultaneously to provide the overall car rental system functionality. We also need to mention that the Users service provides a simple user interface that allows users to log in and make reservations.
Acme Car Rental represents a small but coherent system. For a real-world application, it might be too complex since it relies on many software stacks that are quite different. However, since our goal is to explain how Quarkus integrates with all these technologies, car rental serves as an excellent learning material.
Implementation
For the implementation of the services of Acme Car Rental, we fix the Quarkus version to 3.15.1, which is the latest released version by the code freeze for this book. Feel free to experiment with the newer versions, but obviously, we cannot guarantee that everything will still work.
Tip
If you decide to try a newer released version of Quarkus by the time of your read, Quarkus also ships a built-in update mechanism that often works with even older versions. Simply run ./mvnw quarkus:update
(Maven), quarkus update
(CLI), or ./gradlew quarkusUpdate
(Gradle) to update your project.
Quarkus also provides the Long-Term Support (LTS) releases that are supported for a longer time than regular releases. It is valuable to users who don’t want to follow regular Quarkus updates that come very quickly. Fortunately for us, the 3.15 release stream is an LTS release! It was started in September 2024, and it’s supported for the next year. If you want to experiment with the latest Quarkus versions, it might be safer to use the latest LTS 3.15.x version, which is considered more stable.
We develop in Java as our primary language. However, we need also to point out that Quarkus supports two alternative JVM languages—Kotlin and Scala (detailed in appendix A). We use JDK version 21, which is the latest JDK LTS release version available at the time of this writing.
Note
Quarkus 3.15.1 requires a minimum of JDK version 17.
The primary build tool we use in car rental is Maven (if you prefer to work with Gradle, see appendix A). The required version of Maven is 3.9.8+. Nevertheless, Quarkus comes with Maven integrated into the projects (Maven wrapper), which handles Maven versioning for you.
Since each chapter examines a particular technology, we want to prioritize the teaching of its software stack and its Quarkus integration in each respective chapter. Nonetheless, for the completeness of your Quarkus learning, we explain the use of Kotlin and Scala together with the Quarkus application building on top of Gradle in appendix A.
Download Quarkus in Action
Ready to keep exploring how Quarkus streamlines cloud-native application development? Download the full e-book courtesy of Red Hat Developer.