Your First Quarkus App: A Simple Java REST API in Minutes
No containers, no Kubernetes. Just a JDK, Maven, and the fastest path to modern Java development.
Over the past months I’ve shared many deep-dive tutorials here, from advanced database tricks to AI-infused applications with LangChain4j. Those guides are great for exploring what Quarkus can do in complex, enterprise-grade scenarios. But I’ve realized some readers might be looking for something simpler. A starting point.
That’s why today I want to step back and walk you through the most basic experience: creating your very first Quarkus application. No containers, no Kubernetes, no extra complexity. Just you, a JDK, and a terminal.
Quarkus is a modern Java framework built for efficiency. Applications start fast, use less memory, and still feel natural to Java developers. You don’t need anything more than a standard JVM to try it out.
In this tutorial, you will:
Create a Quarkus project with Maven.
Run it in development mode and see live coding in action.
Add your own REST endpoint.
Build a native executable for Linux using Mandel.
Let’s get started.
Prerequisites
Make sure you have the following installed:
JDK 11 or newer (JDK 17 or later recommended).
Apache Maven 3.8.1+. This tutorial uses Maven, but you could use Gradle.
An IDE such as IntelliJ IDEA or VS Code.
Verify your setup:
java -version
mvn -version
Create a Quarkus Application
Open a terminal and run:
mvn io.quarkus.platform:quarkus-maven-plugin:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=getting-started \
-DclassName="org.acme.GreetingResource" \
-Dpath="/hello"
This generates a new project under getting-started/
with:
A Maven build (
pom.xml
).A REST endpoint at
/hello
.
Move into the project:
cd getting-started
Run in Development Mode
Start Quarkus in dev mode:
./mvnw quarkus:dev
Quarkus boots in under a second (on my machine 0.754s). In your browser or with curl, try:
curl http://localhost:8080/hello
Output:
Hello from Quarkus REST
Now change the message:
Open
src/main/java/org/acme/GreetingResource.java
.Update the return string to:
return "My first Quarkus app is live!";
Save the file. No restart is needed. Refresh the browser or send a new curl and you can see the live reload message in the server log:
2025-08-29 09:32:46,496 INFO [io.qua.dep.dev.RuntimeUpdatesProcessor] (vert.x-worker-thread-1) Live reload total time: 0.279s
The new message appears instantly. That’s live coding.
Add Your Own Endpoint
Let’s make the app more fun by adding a random fact generator. You still haven’t stopped Quarkus, right! Keep it running.
Create src/main/java/org/acme/FunFactResource.java
:
package org.acme;
import java.util.List;
import java.util.Random;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/funfact")
public class FunFactResource {
private final List<String> facts = List.of(
"A group of flamingos is called a 'flamboyance'.",
"Honey never spoils.",
"The unicorn is the national animal of Scotland.",
"A single cloud can weigh more than 1 million pounds.");
private final Random random = new Random();
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getFunFact() {
return facts.get(random.nextInt(facts.size()));
}
}
Save the file. Without restarting, open:
curl http://localhost:8080/funfact
Each refresh shows a different fact.
Before we move on to the final section, let’s make sure to fix our test case. Open src/test/java/org/acme/GreetingResourceTest.java
and make sure the body assertion checks for the new return String. You can learn more about Quarkus testing in an older post.
package org.acme;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
class GreetingResourceTest {
@Test
void testHelloEndpoint() {
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("My first Quarkus app is live!"));
}
}
Build a Native Executable (Optional)
Quarkus apps run well on a normal JVM. But if you want to see the benefits of native compilation, try this.
Now you really need to stop dev mode (CTRL+C) though.
Quite often one only needs to create a native Linux executable for their Quarkus application (for example in order to run in a containerized environment) and would like to avoid the trouble of installing the proper GraalVM version in order to accomplish this task (for example, in CI environments it’s common practice to install as little software as possible).
To this end, Quarkus provides a very convenient way of creating a native Linux executable by leveraging a container runtime such as Docker or podman. The easiest way of accomplishing this task is to execute:
./mvnw package -Pnative -Dquarkus.native.container-build=true -Dquarkus.container-image.build=true
What happens here:
-Pnative
: Enables the native build profile-Dquarkus.native.container-build=true
: Runs the native build inside a container-Dquarkus.container-image.build=true
:Runs the container build for the native executable
This process will take some time as it involves Ahead-Of-Time (AOT) compilation of the entire application. On my M4 it was only 54.691 s.
You’ll find the produced executable:
./target/getting-started-1.0.0-SNAPSHOT-runner
And yes, you can not start this on MacOS. At least not native. For that, you’d need to containerize it first.
What You’ve Learned
You created a REST API with Quarkus, experienced live coding, and even built a native binary. All of this works with just a standard JDK and Maven. No container, Kubernetes, or special runtime required.
Quarkus runs anywhere Java runs — your laptop, a VM, or a cluster — while giving you the option to optimize for modern platforms.
The next step is to explore persistence, reactive APIs, or messaging. But for now, you’ve got a solid first Quarkus app running. If you want to find more advanced tutorials, feel free to look through the existing ones.