Getting started with Quarkus Flow
This tutorial shows the shortest path to run a Quarkus Flow workflow inside your Quarkus application, using Quarkus-native ergonomics (CDI, build-time discovery, dev mode).
1. Prerequisites
-
Java 17 or newer with
JAVA_HOMEconfigured. -
Maven 3.8+.
-
A Quarkus project. You can generate one with:
mvn io.quarkus:quarkus-maven-plugin:create
2. Add the dependency
Add the Quarkus Flow extension to your application.
<dependency>
<groupId>io.quarkiverse.flow</groupId>
<artifactId>quarkus-flow</artifactId>
<version>0.3.0</version>
</dependency>
3. Define a minimal workflow
Create a Flow subclass. At build time, Quarkus Flow discovers it and makes it injectable
as a CDI bean.
The example below defines a simple workflow that sets a JSON message into the workflow context.
package org.acme;
import static io.serverlessworkflow.fluent.func.dsl.FuncDSL.set;
import jakarta.enterprise.context.ApplicationScoped;
import io.quarkiverse.flow.Flow;
import io.serverlessworkflow.api.types.Workflow;
import io.serverlessworkflow.fluent.func.FuncWorkflowBuilder;
@ApplicationScoped
public class HelloWorkflow extends Flow {
@Override
public Workflow descriptor() {
return FuncWorkflowBuilder.workflow("hello")
// jq expression to set our context to the JSON object `message`
.tasks(set("{ message: \"hello world!\" }"))
.build();
}
}
4. Expose the workflow via HTTP
There are two ergonomic options depending on how much control you want over the injection point.
4.1. Inject the Flow subclass (recommended)
Inject the HelloWorkflow bean directly and use the convenience methods on Flow
to start a new instance.
package org.acme;
import java.util.Map;
import java.util.concurrent.CompletionStage;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.jboss.resteasy.reactive.ResponseStatus;
@Path("/hello")
@ApplicationScoped
public class HelloResource {
@Inject
HelloWorkflow hello; // inject the Flow subclass
@GET
@ResponseStatus(200)
public CompletionStage<Message> hello() {
return hello
.startInstance(Map.of()) // convenience on Flow
.thenApply(w -> w.as(Message.class).orElseThrow());
}
}
4.2. Inject the compiled definition (advanced)
If you need the compiled WorkflowDefinition, you can inject it by FQCN instead.
This is useful when you want to work at a more generic level (for example, selecting
workflows dynamically).
import io.smallrye.common.annotation.Identifier;
import io.serverlessworkflow.impl.WorkflowDefinition;
@Inject
@Identifier("org.acme.HelloWorkflow") // FQCN of the workflow class
WorkflowDefinition helloDef;
5. Run the application
Start Quarkus in dev mode:
./mvnw quarkus:dev
Then invoke the HTTP endpoint you exposed (for example, if HelloResource is mapped to
/hello):
curl http://localhost:8080/hello
You should see a JSON response with the message produced by the workflow.
6. What’s next?
-
Java DSL cheatsheet — common patterns and snippets.
-
Agentic workflows with LangChain4j — agents, critique/revise loops, HITL.
-
Use messaging and events — emit/listen event patterns.
-
Extension Configuration Reference — all config keys and generated tables.