Repository navigation
Native images
The Quarkus integration of VanillaBP builds into a native image. An application which uses it needs nothing beyond the usual Quarkus command. This page is about what an image carries for you, and what a profile still decides once the binary exists. A resource which is not in the image gives no warning. It is simply not there, and your application runs on its defaults.
-
Building the image
One command, and nothing of VanillaBP to configure for it. -
What the extension puts into the image
The BPMN files of your workflow modules and the configuration files they ship, wherever those files live. -
What a profile decides once the image is built
Almost everything is read when the binary runs. Know the two exceptions before you package. -
Your application's own profile files
A binary does not readapplication-tenant.yamlby itself. There are three ways to get at the values in it. -
What your BPMS adapter adds
Each BPMS (business process management system) adapter registers what its own client needs. One of them does not support native images at all.
mvn package -Dquarkus.native.enabled=true -Dquarkus.native.container-build=trueThere is nothing to configure for VanillaBP. The container build needs no GraalVM on your machine, because the builder image brings one.
A native image carries only the resources it was told about during the build. VanillaBP provides two lists of them.
The first list holds the BPMN files of every workflow module. They are indexed during the build anyway. The reason: resources-location is read when the application runs, and at that point a packaged application cannot be searched for **/*.bpmn.
The second list holds the configuration files of every workflow module. This is the file named after the workflow module ID and every profile-specific variant of it. They can be at the classpath root or in a directory named after the ID, as .yaml, .yml and .properties. They can be in your application's own archive or in the JAR of a workflow module which is packaged as its own Maven module. Dev mode watches the same list for hot reload, and the image builder gets it unchanged. Think of a file which dev mode watches but which is missing from the binary. Its workflow module would use its settings while you develop, and quietly use the defaults in production. So there is one list and not two.
MongoDB is optional here. In a native image "optional" is stricter than on the JVM, because GraalVM resolves every method a linked class refers to during the build. Think of a single call into the MongoDB driver, made from code which every application runs. It would break the build of an application which keeps its workflow aggregates in a relational database. So VanillaBP reaches everything MongoDB-specific through beans which the extension registers only when quarkus-mongodb-client is on the classpath. An application without MongoDB never links the driver. An application with MongoDB keeps the startup checks it had before. One of them is the warning about a deployment which is not a replica set.
Configuration is read when the binary runs, not when it is built. The last two rows are the exceptions:
| Where a value lives | In a running binary |
|---|---|
| a system property or an environment variable | read, as on the JVM |
application.yaml and the %profile: sections in it |
read; -Dquarkus.profile=<name> at the binary picks the section |
a workflow module's <id>.yaml or <id>.properties and their <id>-<profile> variants |
read; -Dquarkus.profile=<name> at the binary picks among them, and a variant wins over the plain file exactly as on the JVM |
application-<profile>.yaml or application-<profile>.properties
|
not read, see below |
| what Quarkus itself decides during the build, such as the kind of a datasource or which extensions are in | fixed in the image; a profile which changes one of those needs an image of its own |
Quarkus warns when a binary is started with a different profile than the one its image was built with. This warning is about the last row. Read it, do not silence it. Everything above that row does follow the profile of the run.
Quarkus makes the list of its own configuration files during the image build. So application-tenant.yaml is part of a binary only if tenant was active during that build. When you choose a profile at the start of the binary, it switches values and sections. It does not add another file. On the JVM the same application does read that file, so the difference is easy to miss. For this reason a native build of a VanillaBP application reports which of those files it leaves out. It also names three ways to get at the values in them:
- Move the values into a
%tenant:section ofapplication.yaml. That file is part of every image, and-Dquarkus.profile=tenantat the binary picks the section. One image then serves every profile. This is the smallest change when a profile only carries values. - Build one image per profile,
-Dquarkus.profile=tenant. The binary then needs no argument at all when it starts. Use this way when the profile also changes something Quarkus decides during the build. - Keep the file. Put it into the image with
quarkus.native.resources.includes=application-*.yaml, and name it when the binary starts,-Dsmallrye.config.locations=application-tenant.yaml.
VanillaBP does not load those files itself, on purpose. They belong to Quarkus. A second loading mechanism next to the one of Quarkus would bring its own order of precedence and its own surprises. And each of the three ways above is a one-line change in your application.
Measured on 2026-08-30 with Quarkus 3.39, on the binary of the platform's own native-image test: an application-tenant.yaml inside the image is still not read when the binary is started with only -Dquarkus.profile=tenant. It is read as soon as -Dsmallrye.config.locations names it. So putting the file into the image is not enough by itself, and this is why the third way needs two settings and not one. The configuration files of workflow modules behave differently. The reason is that the extension puts them into the image and VanillaBP loads them itself.
An adapter registers what its own client needs. Its wiki says what that is and what it costs:
- Camunda 8 registers the message bundles and schemas of the BPMN parser, the gRPC providers behind the service loader, and the types Jackson uses to build the cluster's answers: native images.
- Camunda 7 does not support native images at all, and that will not change: Quarkus: JVM mode only.
