Difficulty: beginner
Estimated Time: 15 minutes

This exercise demonstrates how your Quarkus application can utilize the Qute Templating Engine feature to build type-safe, server-side templates which can be rendered at will in Quarkus applications.


Qute is a templating engine designed specifically to meet Quarkus' needs. The usage of reflection is minimized to reduce the size of native images. The API combines both the imperative and the non-blocking reactive style of coding. In the development mode, all files located in src/main/resources/templates are watched for changes and modifications are immediately visible. Furthermore, we try to detect most of the template problems at build time. In this exercise, you will learn how to easily render templates in your application.

The Qute engine renders templates (ordinary files with things like Hello {name}!). The expression {name} embedded in the template is replaced with the value of the corresponding value passed in as context (a simple string, or perhaps a Map of key/value pairs). Due to its type-safe goals, the engine will attempt to validate expressions during the build, to catch any errors or typos or other mismatched expressions.

Qute is currently an experimental feature in Quarkus. There is no guarantee of stability nor long term presence in the platform until the solution matures.

An introduction guide and a more comprehensive reference guide are available.

Let's get going!

Congratulations! Qute provides a powerful, flexible, type-safe and reactive way to render templates using ideas and mechanisms familiar to Java developers. To learn more about Qute, please refer to the Qute reference guide.

Additional Resources

If you’re interested in helping continue to improve Quarkus, developing third-party extensions, using Quarkus to develop applications, or if you’re just curious about it, please check out these links:

Using the Qute Templating Engine

Step 1 of 6

Step 1

Inspect Java runtime

An appropriate Java runtime has been installed for you. Ensure you can use it by running this command:

If the command fails, wait a few moments and try again (it is installed in a background process and make take a few moments depending on system load).

$JAVA_HOME/bin/java --version

The command should report the version in use, for example (the versions and dates may be slightly different than the below example):

openjdk 11.0.10 2021-01-19
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.10+9)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.10+9, mixed mode)

Create sample project

Let's create the basic Quarkus Hello World application and include the necessary qute extensions. Click this command to create the project:

cd /root/projects/quarkus && mvn io.quarkus:quarkus-maven-plugin:2.0.0.Final:create \ -DprojectGroupId=org.acme \ -DprojectArtifactId=qute \ -Dextensions="quarkus-resteasy-qute,quarkus-vertx-web,quarkus-qute,quarkus-scheduler"

The first time you create an app, new dependencies may be downloaded via maven and take a minute or so. This should only happen once, after that things will go even faster.

This will use the Quarkus Maven Plugin and generate a sample Qute project for you in the qute subdirectory and include the quarkus-resteasy-qute extension which includes the templating engine and integration with JAX-RS via RestEasy. We've also included a few other extensions we'll use later on.

Once generated, look at the qute/pom.xml. You will find the import of the Quarkus BOM, allowing to omit the version on the different Quarkus dependencies.

Start the app

Let's begin Live Coding. Click on the following command to start the example app in Live Coding mode:

cd /root/projects/quarkus/qute && \ mvn quarkus:dev -Dquarkus.http.host=

You should see:

__  ____  __  _____   ___  __ ____  ______
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
INFO  [io.quarkus] (Quarkus Main Thread) qute 1.0.0-SNAPSHOT on JVM (powered by Quarkus x.xx.x.Final) started in x.xxxs. Listening on:
INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, mutiny, qute, resteasy, resteasy-qute, scheduler, smallrye-context-propagation, vertx, vertx-web]

The first time you build the app, new dependencies may be downloaded via maven. This should only happen once, after that things will go even faster.

Note the amazingly fast startup time! The app is now running "locally" (within the Linux container in which this exercise runs).

Test that the app is running by accessing the sample page using this link. You should see

Qute sample

This page is rendered using the qute/src/main/resources/templates/page.qute.html HTML template. If you look closely you can see a {name ?: "Qute"} directive that renders the passed-in name query present in the qute/src/main/java/org/acme/SomePage.java class and passed into the template renderer in the data() method, making the name variable available to the renderer and returning the rendered HTML to your browser. If you pass a different name, say, Jerry using this link (which adds ?name=Jerry to the URL) you'll see the new name rendered via the Qute template:

Qute sample

Let's keep the app running and continue using Quarkus' Live Coding feature. Changes you make are immediately available in the running app when developing Quarkus apps.

Create basic template

We’ll start by creating a new and very simple text-based template.

Click qute/src/main/resources/templates/hello.txt to create an empty template file.

Finally, click the Copy to Editor to add the template code:

Hello {name}!
  • {name} is a value expression that is evaluated when the template is rendered.

By default, all files located in the src/main/resources/templates directory and its subdirectories are registered as templates. Templates are validated during startup and watched for changes in the development mode.

Create REST endpoint to access template

Now let’s inject the "compiled" template in the resource class.

Click here to open qute/src/main/java/org/acme/HelloResource.java.

Click the Copy to Editor to update our HelloResource class:

package org.acme;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.Template;

public class HelloResource {

    Template hello;

    public TemplateInstance get(@QueryParam("name") String name) {
        return hello.data("name", name);
  • If there is no @ResourcePath qualifier provided when @Injecting, the field name is used to locate the template. In this particular case, we’re injecting a template with path templates/hello.txt.
  • Template.data() returns a new template instance that can be customized before the actual rendering is triggered. In this case, we put the name value under the key name. The data map is accessible during rendering.
  • Note that we don’t trigger the rendering - this is done automatically by a special ContainerResponseFilter implementation.

Test endpoint

With our application already running in Live Coding mode, we can render the template by calling the endpoint. Click the command below to test it:

curl http://localhost:8080/hello?name=James

You should see:

Hello James!

The template was rendered, replacing the {name} expression with the value passed in with hello.data("name", name);

This is the basic syntax and idea, which originated with other popular and well-known technologies:

Let's now explore some new features based on Quarkus principles.