Getting Started with Quarkus

This section documents Quarkus 3.39.x (current) with 3.33.x LTS as the production recommendation, on the Java 17+ baseline, as published at the official Quarkus guides — which are the reference these pages are written and verified against.

Quarkus 4 raises the baseline to Java 21 (first release candidate planned for end of September 2026, see the Quarkus blog); readers upgrading past 3.39.x/3.33.x LTS should expect that change.

This content was generated with the assistance of AI and should be verified against those official guides before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

Quarkus is a Java framework designed from the ground up for containers and Kubernetes rather than for long-lived application servers. This page introduces the problem it solves, the current release model, the four ways to scaffold a project, the layout each one produces, a first REST endpoint written against Quarkus REST, and the everyday inner loop — create, dev, test, package, deploy — that the rest of the Quarkus pages in this section build on.

The problem Quarkus solves

Traditional Java web stacks were designed for a world of long-running application servers: a JVM boots once, warms up its JIT compiler over minutes, and then serves traffic for days or weeks, so a slow start and a large memory footprint barely matter. That trade-off inverts completely in a Kubernetes-native, container-per-request or scale-to-zero world: a pod that takes ten seconds to become ready fails a tight liveness probe, a rolling deployment or autoscaling event that spins up dozens of replicas pays that ten seconds on every one of them, and a large resident-memory footprint (RSS) per instance directly caps how many containers fit on a node — which is exactly what a cloud bill measures. Quarkus attacks both numbers directly: it moves as much work as possible — classpath scanning, annotation processing, bean wiring, reflection configuration — from application startup to build time, so what ships to production is a pre-computed, close-to-final application rather than one that still has to discover its own shape when the JVM boots. The result, on the JVM alone, is startup measured in tenths of a second and materially lower RSS than an equivalent traditional stack; compiled further to a GraalVM native image, the same application starts in single-digit milliseconds with an even smaller footprint, at the cost of a longer build and some reflection-related caveats covered in depth on a dedicated native-image page in this section. Both modes target the same goal: more instances of the application per node, faster horizontal scaling, and a Java runtime that behaves the way Kubernetes' own health checks and autoscalers expect it to.

Quarkus ships a minor release every four to six weeks and designates a Long Term Support (LTS) release roughly every six months for teams that want a longer support window before their next upgrade. As of this writing the current release is 3.39.x, with 3.33.x LTS the recommended baseline for production deployments that prefer stability over the latest minor. Both lines target Java 17 as the minimum baseline today; Quarkus 4 raises that baseline to Java 21, as already noted in the disclaimer above.

Creating a project

Quarkus offers four equally supported ways to scaffold a new project. All four produce the same project shape; pick whichever fits the environment at hand.

Quarkus CLI

The Quarkus CLI is the most direct route once installed. Install it with SDKMAN!:

sdk install quarkus

Then scaffold a Maven project:

quarkus create app com.example:demo
cd demo

The quarkus-maven-plugin

No separate install is needed when Maven is already available — invoke the plugin directly, pinned to a specific Quarkus version:

mvn io.quarkus.platform:quarkus-maven-plugin:3.39.0:create \
    -DprojectGroupId=com.example \
    -DprojectArtifactId=demo \
    -Dextensions="rest"
cd demo

Gradle

The same Quarkus CLI generates a Gradle project with a flag, or the CLI’s create-app goal can be driven directly against Gradle tooling:

quarkus create app com.example:demo --gradle
cd demo

code.quarkus.io

code.quarkus.io is Quarkus' equivalent of Spring Initializr: a web-based generator where the group/artifact coordinates, build tool (Maven or Gradle), Java version, and extensions are picked from checkboxes, producing a downloadable zip with the same layout described below. It is the easiest starting point when no CLI is installed yet.

The generated project layout

Whichever route was used, the result is the same Maven (or Gradle) project:

$ tree demo
demo
├── .dockerignore
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
│   ├── main
│   │   ├── docker
│   │   │   ├── Dockerfile.jvm
│   │   │   ├── Dockerfile.legacy-jar
│   │   │   ├── Dockerfile.native
│   │   │   └── Dockerfile.native-micro
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── GreetingResource.java
│   │   └── resources
│   │       └── application.properties
│   ├── native-test
│   │   └── java
│   └── test
│       └── java
│           └── com
│               └── example
│                   └── GreetingResourceTest.java
  • pom.xml — imports the quarkus-bom and declares the requested extensions (rest by default) as plain dependencies with no explicit versions, since the BOM pins them all together; also wires in the quarkus-maven-plugin, which drives every ./mvnw quarkus:* goal used below.

  • src/main/java — application code; the generator seeds it with a single GreetingResource REST endpoint.

  • src/main/resources/application.properties — externalized configuration as plain key=value pairs, for example quarkus.http.port=8080; this page keeps configuration at that level, with annotation-driven configuration covered separately elsewhere in this section.

  • src/main/docker/ — ready-made `Dockerfile`s for each packaging mode this page and later ones cover: a regular JVM fast-jar image, a legacy uber-jar image, a native-image build, and a minimal native "micro" base image.

  • src/test/java — JVM-mode tests, run with ./mvnw test against the packaged or dev-mode application.

  • src/native-test/java — tests that only make sense against a compiled native executable (starts out empty; populated once native-image testing is introduced).

  • .dockerignore — keeps target/, IDE metadata, and other build artifacts out of the Docker build context used by the Dockerfiles above.

  • mvnw / mvnw.cmd — the Maven wrapper, so ./mvnw …​ works without a locally installed Maven matching the project’s expected version.

The first REST endpoint

The generator’s GreetingResource is written against Quarkus REST — Quarkus' own JAX-RS implementation, built on jakarta.ws.rs, not the older RESTEasy Classic stack:

package com.example;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello from Quarkus REST";
    }
}

Live coding with quarkus dev

Start the application in dev mode:

./mvnw quarkus:dev

This boots the application, opens the Dev UI at http://localhost:8080/q/dev/, and enables live coding: editing GreetingResource.java — say, changing the returned string — and then simply refreshing http://localhost:8080/hello in a browser (or re-issuing curl http://localhost:8080/hello) recompiles and reloads the change on that next request, with no manual restart and no separate build step. This edit-save-refresh loop, rather than a slow "stop the JVM, rebuild, restart" cycle, is one of the concrete productivity gains the build-time-work philosophy from the first section buys in practice.

Adding an extension

Extensions are the unit of integration in Quarkus — a datasource, a messaging connector, health checks, and so on each arrive as one. Add one with the Maven plugin:

./mvnw quarkus:add-extension -Dextensions="quarkus-smallrye-health"

or, equivalently, with the CLI:

quarkus extension add smallrye-health

Either form edits pom.xml to add the corresponding dependency; dev mode picks it up automatically the next time a request triggers a rebuild, with no restart required.

Running and packaging

Besides ./mvnw quarkus:dev for local development, a packaged application runs as a plain executable jar:

./mvnw package
java -jar target/quarkus-app/quarkus-run.jar

./mvnw package produces a fast-jar layout under target/quarkus-app/, not a single uber-jar:

target/quarkus-app
├── app/
├── lib/
├── quarkus/
└── quarkus-run.jar

quarkus-run.jar is a thin launcher; lib/ holds the application’s dependency jars (split into a boot and a main classpath internally so unchanging third-party jars are not repacked on every build); app/ holds the project’s own compiled classes; quarkus/ holds Quarkus' own generated bootstrap and build-time metadata. This split lets container image layers cache lib/ separately from the frequently-changing app/ layer, which is one reason fast-jar images rebuild and push faster than a single fat jar would — the full mechanics of fast-jar, its --mutable-jar and uber-jar alternatives, and its interaction with the Dockerfiles under src/main/docker/ are covered in depth on a packaging-focused page later in this section.

The inner loop

Day-to-day Quarkus development cycles through the same five steps regardless of which of the four scaffolding routes started the project:

flowchart LR A[create] --> B[dev] B --> C[test] C --> D[package] D --> E[deploy] E -.-> B

create scaffolds the project once; from there, quarkus dev and the live-coding loop described above dominate day-to-day work, ./mvnw test (or the native-test module, for native-image-specific tests) validates changes, ./mvnw package produces the target/quarkus-app/ layout described above, and deploy ships one of the src/main/docker/ images to its target environment — after which the loop returns to dev for the next change.