Native image containers with Rockcraft plugins

In this series, I have shown how Rockcraft’s Maven and Gradle plugins make the task of producing development-time container images of your application, effortless and iteration-friendly.
The need to run a Java application within a bare-minimal runtime comes from the cloud-native and edge-computing worlds, where optimizing away unwanted dependencies to reduce the application’s memory footprint is a common effort. In that context, the Rockcraft plugins let us create custom application runtime images for non-modular and modular Java applications.
There is another problem that afflicts all kinds of Java applications. By virtue of the platform-independent design of the Java platform, applications often suffer from a slow/delayed startup. There is a category of modern Java applications, especially from the cloud-native world, with sub-second startup-time requirements, where this problem becomes critical.
GraalVM Native Image offers a promising solution to the slow-startup problem. GraalVM compiles an application into a platform-native executable binary, enabling application startup right at launch. With compile-time class loading, ahead-of-time compilation of code and minimal-to-no garbage collection, GraalVM native image suits short-lived Java applications very well.
Native image containers with the Rockcraft Maven/Gradle plugins
For your Maven and Gradle based applications, the Rockcraft plugins let you create container images packaging the self-sufficient native-image binary produced by GraalVM. The native image compilation happens on the host.
If you don’t have the pre-requisite setup for Rockcraft, please follow instructions here.
Step 1: Installing GraalVM Community Edition for JDK
For Ubuntu versions 24.04 and above, GraalVM Community Edition is available as a snap package. For the purpose of this demo exercise, we need a GraalVM installation.
snap install graalvm-jdk --channel=v21
stable and betachannels let you install the latest and development GraalVM CE versions respectively. As the name suggests, channel v21 installs GraalVM for JDK 21.This command installs a GraalVM JDK at /snap/graalvm-jdk/current/graalvm-ce.
Step 2: Clone your project
Let’s use the spring-petclinic project for this demo.
git clone https://github.com/spring-projects/spring-petclinic && \
cd spring-petclinic
Step 3: Configure the native compilation plugin
For Maven-based projects please add the following build plugin. The spring-petclinic project has this build plugin added.
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
For a Gradle-based project add this plugin. The spring-petclinic project this plugin added.
plugin {
...
id 'org.graalvm.buildtools.native' version '0.10.6'
}
Step 4: Configure the Rockcraft plugin
Make sure the Rockcraft Maven plugin is also added to the pom.xml in your Maven project.
<plugin>
<groupId>io.github.rockcrafters</groupId>
<artifactId>rockcraft-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<configuration>
<createService>false</createService>
</configuration>
<goals>
<goal>create-rock</goal>
<goal>build-rock</goal>
<goal>push-rock</goal>
</goals>
</execution>
</executions>
</plugin>
For your Gradle project, make sure the Rockcraft plugin is configured after the GraalVM plugin.
plugin {
...
id 'org.graalvm.buildtools.native' version '0.10.6'
id 'io.github.rockcrafters.rockcraft' version '1.2.1'
}
Step 5: Running maven/gradle
The GraalVM plugins will need the location of a GraalVM installation in your environment. Use the GRAALVM_HOME environment variable to point to the installation we did in step 1.
export GRAALVM_HOME=/snap/graalvm-jdk/current/graalvm-ce
For Maven projects, run this command:
mvn -Pnative native:compile -DskipTests install
The -Pnative native:compile options trigger the native image compilation using the GraalVM installation pointed to by GRAALVM_HOME.
For Gradle-based projects run the following command using the packaged gradlew wrapper.
./gradlew nativeCompile push-rock -i
Step 6: Run the application native image
The newly pushed docker image can now be located
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
petclinic 3.5.0-SNAPSHOT 4e46eb04bc44 About a minute ago 336MB
petclinic latest 4e46eb04bc44 About a minute ago 336MB
Notice the bloated size! The space-time trade-off is obvious.
Now, let’s locate the native executable in this image and run it.
$ docker run petclinic exec pebble ls /*petclinic*
spring-petclinic
$ docker --network=host run petclinic exec /spring-petclinic
|\ _,,,--,,_
/,`.-'`' ._ \-;;,_
_______ __|,4- ) )_ .;.(__`'-'__ ___ __ _ ___ _______
| | '---''(_/._)-'(_\_) | | | | | | | | |
| _ | ___|_ _| | | | | |_| | | | __ _ _
| |_| | |___ | | | | | | | | | | \ \ \ \
| ___| ___| | | | _| |___| | _ | | _| \ \ \ \
| | | |___ | | | |_| | | | | | | |_ ) ) ) )
|___| |_______| |___| |_______|_______|___|_| |__|___|_______| / / / /
==================================================================/_/_/_/
:: Built with Spring Boot :: 3.5.0
...
...
2025-08-29T15:40:36.664Z INFO 18 --- [ main] o.s.s.petclinic.PetClinicApplication :
Started PetClinicApplication in 0.229 seconds (process running for 0.233)
The application comes up in ~0.23 seconds and is reachable at http://localhost:8080.
Thanks for reading! Below are the screen-casts for the Maven and Gradle workflows.




