How to Build a Native Spring Boot Executable with GraalVM and Docker
Learn to compile a Spring Boot 3.5.6 application into a fast-starting native binary using GraalVM, configure the environment, add Maven plugins, write simple test code, and package the result into a lightweight Docker image, achieving dramatically reduced startup time and image size.
Overview
Spring Boot applications are normally packaged as JAR files that require a JRE at runtime, leading to large Docker images and slow startup. GraalVM can compile Java code ahead‑of‑time (AOT) into a native executable, which dramatically reduces both image size and launch time.
Prerequisites
GraalVM distribution based on JDK 21
Maven 3.9.11
Spring Boot 3.5.6
Docker 26.1.4
Environment configuration
Add the following lines to ~/.bashrc (or the appropriate shell profile) and reload the file:
export GRAALVM_HOME=/path/to/graalvm
export JAVA_HOME=$GRAALVM_HOME
export PATH="$JAVA_HOME/bin:$PATH"
source ~/.bashrcProject setup
The Maven pom.xml defines the Java version, Spring Boot starter, and the GraalVM build plugins.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.uav</groupId>
<artifactId>springboot-native</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.6</version>
</parent>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.uav.BootApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>Application code
Simple Spring Boot entry point and a REST controller.
package com.uav;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BootApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
} package com.uav;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@RequestMapping("/users")
public String getUsers() {
return "This is a list of users";
}
}Build native executable
Compile the project with the native profile. The command produces a native binary in the target directory.
mvn -Pnative native:compileDocker image
Create a minimal Docker image that contains only the native binary.
FROM ubuntu:jammy
COPY target/springboot-native springboot-native
ENTRYPOINT ["/springboot-native"]Build and run the image:
docker build . --tag my-app
docker run -p 8080:8080 my-appResults
The native image starts in roughly 0.065 seconds, and the Docker image size is about 70 % smaller than a traditional JAR‑plus‑JRE image.
Dunmao Tech Hub
Sharing selected technical articles synced from CSDN. Follow us on CSDN: Dunmao.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
