Skip to content
Learni
View all tutorials
Backend

How to Master Quarkus for Microservices in 2026

Lire en français

Introduction

In 2026, Quarkus dominates the Java framework landscape for microservices thanks to its GraalVM native compilation, slashing startup times to under 10 ms and memory usage by 80% compared to Spring Boot. Ideal for Kubernetes and serverless, it delivers supersonic subatomic Java: lightning-fast builds, hot reload in dev mode, and modular extensions for Kafka, gRPC, or OpenTelemetry.

This expert tutorial walks you step-by-step through building a complete microservice: reactive REST API, persistence with Hibernate Reactive, unit tests, native builds, and Kubernetes deployment. Every line of code is production-ready and copy-pasteable. Picture a framework that compiles your app into a standalone binary like Go or Rust—but in pure Java. That's Quarkus. By the end, you'll command advanced configs for production scaling. (142 words)

Prerequisites

  • JDK 17+ (GraalVM 22+ recommended for native)
  • Maven 3.9+ or Gradle 8+
  • Docker and Kubernetes (minikube for testing)
  • Advanced knowledge: Java 21 records/sealed classes, reactivity (Mutiny), Hibernate ORM
  • IDE: IntelliJ with Quarkus Tools or VS Code

Create the Quarkus Project

terminal
mkdir quarkus-microservice && cd quarkus-microservice
quarkus create app --extensions=resteasy-reactive,hibernate-reactive-panache,quarkus-smallrye-health,quarkus-container-image-docker,quarkus-kubernetes \
  com.example:quarkus-microservice:1.0.0-SNAPSHOT

# Alternative Maven CLI si quarkus CLI non installé
mvn io.quarkus.platform:quarkus-maven-plugin:3.15.1:create \
  -DprojectGroupId=com.example -DprojectArtifactId=quarkus-microservice \
  -Dextensions="resteasy-reactive,hibernate-reactive-panache,quarkus-smallrye-health,quarkus-container-image-docker,quarkus-kubernetes" \
  -DnoCode

This command initializes a project with reactive REST, reactive PostgreSQL persistence (auto-provisioned via Dev Services), health checks, native Docker builds, and Kubernetes manifests. The --noCode flag skips boilerplate so you can customize everything. Tip: Install the quarkus CLI via brew or SDKMAN for ease.

Generated Project Structure

The skeleton includes src/main/java for JAX-RS resources and Panache entities, application.properties for configs, and pom.xml with extensions. Dev Services auto-starts Postgres in dev without manual setup—pure Quarkus magic. Hot reload with ./mvnw quarkus:dev: edit code, auto-refresh in <1s, like Vite for Java.

Define the Entity and Repository

src/main/java/com/example/Product.java
package com.example;

import io.quarkus.hibernate.reactive.panache.PanacheEntityBase;
import io.smallrye.mutiny.Uni;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;

@Entity
public class Product extends PanacheEntityBase {
    @Id @GeneratedValue
    public Long id;
    public String name;
    public Double price;

    public static Uni<Product> findByName(String name) {
        return find("name", name).firstResult();
    }

    public static Uni<Long> deleteByName(String name) {
        return delete("name", name);
    }
}

Extends PanacheEntityBase for reactive CRUD with Mutiny (Uni/Multi). Built-in static repository avoids DAO boilerplate. Pitfall: Always wrap in Uni for non-blocking; @GeneratedValue auto-increments IDs.

Implement the REST Resource

src/main/java/com/example/ProductResource.java
package com.example;

import io.smallrye.mutiny.Uni;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.util.List;

@Path("/products")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ProductResource {

    @GET
    public Uni<List<Product>> getAll() {
        return Product.listAll();
    }

    @GET
    @Path("{id}")
    public Uni<Response> getById(@PathParam("id") Long id) {
        return Product.findById(id)
                .onItem().transform(product -> product != null ? Response.ok(product) : Response.status(404, "Not found"))
                .onFailure().transform(e -> Response.status(500, e.getMessage()));
    }

    @POST
    public Uni<Response> create(Product product) {
        return product.persist().map(ignore -> Response.created(null).build());
    }

    @DELETE
    @Path("{id}")
    public Uni<Response> delete(@PathParam("id") Long id) {
        return Product.deleteById(id).map(deleted -> Response.noContent().build());
    }
}

Reactive JAX-RS resource: Uni for async handling. Fluid Mutiny chains manage 404/500 errors. @PathParam for dynamic routes. Pro advantage: Zero XML, auto CDI injection, horizontal scaling without blocking.

Database Configuration

Dev Services provisions in-memory Postgres. Override in prod with env vars. Health checks exposed at /q/health for Kubernetes readiness probes.

Advanced Configuration File

src/main/resources/application.properties
quarkus.datasource.db-kind=postgresql
quarkus.datasource.reactive.url=postgresql://localhost:5432/microservice
quarkus.datasource.username=quarkus
quarkus.datasource.password=quarkus

quarkus.hibernate-reactive.database.generation=drop-and-create
quarkus.log.level=INFO

%prod.quarkus.container-image.build=true
%prod.quarkus.container-image.group=learni
%prod.quarkus.kubernetes.deploy=true

quarkus.smallrye-health.root-path=/q/health

# Native hints pour GraalVM
quarkus.native.additional-build-args=--report-unsupported-elements-at-runtime

Profiled configs with %prod for build/deploy. drop-and-create in dev, validate in prod. Native args avoid GraalVM warnings. Pitfall: Don't forget quarkus.container-image.build=true for auto Docker.

Reactive Unit Tests

src/test/java/com/example/ProductResourceTest.java
package com.example;

import io.quarkus.test.junit.QuarkusTest;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.is;

@QuarkusTest
public class ProductResourceTest {

    @Test
    public void testCreateAndGet() {
        Product product = new Product();
        product.name = "Laptop";
        product.price = 999.99;

        given()
                .body(product)
                .contentType(ContentType.JSON)
                .when().post("/products")
                .then()
                .statusCode(201);

        given()
                .when().get("/products")
                .then()
                .statusCode(200)
                .body("[0].name", is("Laptop"));
    }
}

@QuarkusTest mocks DB with H2, injects CDI. RestAssured for HTTP assertions. Covers create/list; add @TestHTTPEndpoint for integration. Expert tip: Tests run 10x faster in parallel than JVM mode.

Native Build and Docker

terminal
./mvnw clean package -Pnative -Dquarkus.native.container-build=true

# Image auto-générée : quay.io/learni/quarkus-microservice:1.0.0-SNAPSHOT-native

# Test local
docker run -i --rm -p 8080:8080 quay.io/learni/quarkus-microservice:1.0.0-SNAPSHOT-native

# Push et deploy K8s
./mvnw deploy -Dquarkus.kubernetes.deploy-mode=openshift # ou kubernetes

native profile compiles to <50MB binary, 0.01s startup. Container build in-Docker for M1/ARM. deploy generates Deployment/Service YAML. Pitfall: First GraalVM build takes 20-30min; cache layers.

Best Practices

  • Strict Profiling: Use %dev, %test, %prod for secrets/env vars; never hardcode.
  • Mutiny Everywhere: Avoid blocking await(); chain onFailure().recoverWith().
  • Lazy Extensions: quarkus-arc for DI, smallrye-opentracing for auto-tracing.
  • Native-Ready: @RegisterForReflection on dynamic classes, test native units.
  • Observability: Enable /q/metrics, Prometheus scrape for K8s HPA.

Common Errors to Avoid

  • IO Blocking: Use Uni.createFrom().emitter() instead of Thread.sleep().
  • GraalVM Reflection: Missing @NativeImageHint crashes runtime; use native-image-agent.
  • Dev Services Leaks: Always ./mvnw clean after dev, or quarkus.devservices.enabled=false.
  • K8s Scaling: Missing /q/health/ready readiness probe = pods pending forever.

Next Steps

Dive into Quarkus Kafka Reactive or gRPC. Master GraalVM with our expert training: Learni Java Cloud-Native Training. Official docs: guide.quarkus.io.