Migration Guide: 0.15.x to 0.16.0

Quarkus Flow 0.16.0 includes several breaking changes:

  • Client routing: HTTP and gRPC task-level routing keys use a new unified format.

  • Runner security: quarkus.flow.runner.security.type is now a required property.

  • Shell execution: run.shell tasks require an explicit command allowlist.

  • Symlinks: Workflow file scanning now skips symbolic links by default.

  • Micrometer metrics: Metrics are now auto-enabled when Micrometer is on the classpath.

  • DSL: FuncForTaskBuilder.collection() now requires SerializableFunction. == Why the change?

In 0.15.1, HTTP, gRPC, and OIDC each had different configuration shapes:

  • HTTP used nested maps (workflow.<name>.task.<taskName>.name), supporting only 2 levels (task, then workflow).

  • gRPC used flat composite keys with colons as task separators (<namespace>:<name>:<version>:<taskName>), supporting 3 levels.

  • OIDC had its own naming convention, separate from both.

This inconsistency made configuration confusing and prevented simple name-only keys for gRPC.

0.16.0 introduces a unified ClientNamingConvention and ClientConfigCascade shared by all three protocols, with a consistent .task. separator and support for namespace-aware, version-aware routing at all levels.

Resolution cascade

All protocols now resolve client names using the same 6-level progressive specificity cascade. The first match wins:

Priority Level Key format

1

Task (full)

namespace:name:version.task.taskName

2

Task (medium)

namespace:name.task.taskName

3

Task (short)

name.task.taskName

4

Workflow (full)

namespace:name:version

5

Workflow (medium)

namespace:name

6

Workflow (short)

name

If no task name is provided, priorities 1-3 are skipped.

What changed

HTTP client routing

Before (0.15.1) After (0.16.0)

Nested map: workflow.<name>.task.<taskName>.name

Flat composite key: workflow."<name>.task.<taskName>".name

Workflow-level only by name

Workflow-level by name, namespace:name, or namespace:name:version

2-level resolution (task, then workflow)

6-level resolution cascade

gRPC client routing

Before (0.15.1) After (0.16.0)

Task separator was : (colon)

Task separator is .task.

No short (name-only) key

Short key supported (<name>)

3-level resolution + 2 fallbacks

6-level resolution + 2 fallbacks

Step-by-step migration

1. Update HTTP task-level routing properties

Workflow-level HTTP properties using only the workflow name are unchanged:

# No change needed
quarkus.flow.http.client.workflow.orders.name=secureA

Task-level HTTP properties must change from nested format to flat composite key format:

# Before (0.15.1) — nested task sub-key
quarkus.flow.http.client.workflow.orders.task.payment.name=secureB

# After (0.16.0) — flat composite key with .task. separator
quarkus.flow.http.client.workflow."orders.task.payment".name=secureB

2. Update gRPC task-level routing properties

Workflow-level gRPC properties are unchanged:

# No change needed
quarkus.flow.grpc.client."org.acme:grpcGreeting:0.0.1".name=my-channel
quarkus.flow.grpc.client."org.acme:grpcGreeting".name=my-channel

Task-level gRPC properties must replace the trailing colon with .task.:

# Before (0.15.1) — colon task separator
quarkus.flow.grpc.client."org.acme:grpcGreeting:0.0.1:greet".name=my-channel

# After (0.16.0) — .task. separator
quarkus.flow.grpc.client."org.acme:grpcGreeting:0.0.1.task.greet".name=my-channel

3. Verify

Rebuild your project and run your tests:

mvn clean verify

If you have unrecognized configuration key warnings at startup, check for any remaining old-format properties.

New capabilities

Name-only keys (short keys)

Both HTTP and gRPC now accept simple name-only keys. This covers the common case where there is no namespace or version ambiguity:

# Works for both HTTP and gRPC
quarkus.flow.http.client.workflow.orders.name=secureA
quarkus.flow.grpc.client.orders.name=my-channel

Namespace and version-aware routing

When multiple namespaces define workflows with the same name, use a more specific key:

# Medium — namespace:name
quarkus.flow.http.client.workflow."acme:orders".name=secureA

# Full — namespace:name:version
quarkus.flow.http.client.workflow."acme:orders:1.0.0".name=secureA

The same applies to gRPC and OIDC.

Runner security type is now required

In 0.15.x, quarkus.flow.runner.security.type defaulted to none. In 0.16.0, this property has no default — you must set it explicitly.

This ensures that security is a deliberate configuration choice, not an implicit default that could be accidentally deployed to production.

# Choose one:
quarkus.flow.runner.security.type=none
quarkus.flow.runner.security.type=api-key
quarkus.flow.runner.security.type=oidc

Without this property, the application fails at startup with:

SRCFG00014: The config property quarkus.flow.runner.security.type is required
This only affects applications using the quarkus-flow-runner extension.

Shell execution requires an allowlist

run.shell tasks now require an explicit command allowlist. An empty list (the default) disables all shell execution.

If your workflows invoke shell commands, add the allowed executables:

quarkus.flow.run.shell.allowed-commands=curl,jq,grep

Without this, run.shell tasks fail at runtime.

Micrometer metrics auto-enabled

In 0.15.x, Micrometer metrics required quarkus.flow.metrics.enabled=true to activate. In 0.16.0, metrics are enabled automatically when Micrometer is on the classpath.

To disable:

quarkus.flow.metrics.enabled=false

DSL: collection() requires SerializableFunction

FuncForTaskBuilder.collection() now accepts SerializableFunction<T, Collection<V>> instead of Function<T, Collection<V>>.

Lambda expressions passed to .collection() work without changes — Java lambdas implement Serializable when the target interface extends it. If you pass a method reference or an explicit Function<> variable, update the type:

// Before (0.15.x)
Function<MyInput, Collection<Item>> fn = MyInput::getItems;
builder.collection(fn); // compile error in 0.16.0

// After (0.16.0)
SerializableFunction<MyInput, Collection<Item>> fn = MyInput::getItems;
builder.collection(fn);

Workflow file scanning now skips symbolic links by default. This prevents duplicate workflow detection failures on Kubernetes, where ConfigMap volume mounts use internal symlinks.

If your workflows are intentionally provided via symbolic links outside of Kubernetes:

# Runner (runtime)
quarkus.flow.runner.source.follow-symlinks=true

# Core (build-time)
quarkus.flow.definitions.follow-symlinks=true

New features

OpenTelemetry tracing

New quarkus-flow-opentelemetry extension provides distributed tracing for workflow execution. See OpenTelemetry for setup instructions.

File watcher for runtime workflow loading

The runner can now poll for new workflow files at runtime without requiring a pod restart:

# Build-time (requires rebuild)
quarkus.flow.runner.source.watch.enabled=true

# Runtime
quarkus.flow.runner.source.watch.interval=5s

Automatic Kafka configuration in dev mode

When the Kafka connector is present, Quarkus Flow now auto-configures flow-in and flow-out channel defaults in dev mode.

Configurable lease acquire timeout

Durable Kubernetes now supports a configurable timeout for lease acquisition:

quarkus.flow.durable.kube.lease.acquire-timeout=30s