[[howto.native-image.developing-your-first-application]]
= Developing Your First GraalVM Native Application

There are two main ways to build a Spring Boot native image application:

* Using Spring Boot xref:reference:packaging/container-images/cloud-native-buildpacks.adoc[support for Cloud Native Buildpacks] with the https://paketo.io/docs/reference/java-native-image-reference/[Paketo Java Native Image buildpack] to generate a lightweight container containing a native executable.
* Using GraalVM Native Build Tools to generate a native executable.

TIP: The easiest way to start a new native Spring Boot project is to go to https://start.spring.io[start.spring.io], add the `GraalVM Native Support` dependency and generate the project.
The included `HELP.md` file will provide getting started hints.



[[howto.native-image.developing-your-first-application.sample-application]]
== Sample Application

We need an example application that we can use to create our native image.
For our purposes, the simple "Hello World!" web application that's covered in the xref:tutorial:first-application/index.adoc[] section will suffice.

To recap, our main application code looks like this:

include-code::MyApplication[]

This application uses Spring MVC and embedded Tomcat, both of which have been tested and verified to work with GraalVM native images.



[[howto.native-image.developing-your-first-application.buildpacks]]
== Building a Native Image Using Buildpacks

Spring Boot supports building Docker images containing native executables, using Cloud Native Buildpacks (CNB) integration with both Maven and Gradle and the https://paketo.io/docs/reference/java-native-image-reference/[Paketo Java Native Image buildpack].
This means you can just type a single command and quickly get a sensible image into your locally running Docker daemon.
The resulting image doesn't contain a JVM, instead the native image is compiled statically.
This leads to smaller images.

NOTE: The CNB builder used for the images is `paketobuildpacks/builder-jammy-java-tiny:latest`.
It has a small footprint and reduced attack surface. It does not include a shell and contains a reduced set of system libraries.
Use `paketobuildpacks/builder-jammy-base:latest` or `paketobuildpacks/builder-jammy-full:latest` to have more tools available in the image if required.



[[howto.native-image.developing-your-first-application.buildpacks.system-requirements]]
=== System Requirements

Docker should be installed. See https://docs.docker.com/installation/#installation[Get Docker] for more details.
https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user[Configure it to allow non-root user] if you are on Linux.

NOTE: You can run `docker run hello-world` (without `sudo`) to check the Docker daemon is reachable as expected.
Check the xref:maven-plugin:build-image.adoc#build-image.docker-daemon[Maven] or xref:gradle-plugin:packaging-oci-image.adoc#build-image.docker-daemon[Gradle] Spring Boot plugin documentation for more details.

TIP: On macOS, it is recommended to increase the memory allocated to Docker to at least `8GB`, and potentially add more CPUs as well.
See this https://stackoverflow.com/questions/44533319/how-to-assign-more-memory-to-docker-container/44533437#44533437[Stack Overflow answer] for more details.
On Microsoft Windows, make sure to enable the https://docs.docker.com/docker-for-windows/wsl/[Docker WSL 2 backend] for better performance.



[[howto.native-image.developing-your-first-application.buildpacks.maven]]
=== Using Maven

To build a native image container using Maven you should ensure that your `pom.xml` file uses the `spring-boot-starter-parent` and the `org.graalvm.buildtools:native-maven-plugin`.
You should have a `<parent>` section that looks like this:

[source,xml,subs="verbatim,attributes"]
----
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>{version-spring-boot}</version>
</parent>
----

You additionally should have this in the `<build> <plugins>` section:

[source,xml,subs="verbatim,attributes"]
----
<plugin>
	<groupId>org.graalvm.buildtools</groupId>
	<artifactId>native-maven-plugin</artifactId>
</plugin>
----

The `spring-boot-starter-parent` declares a `native` profile that configures the executions that need to run in order to create a native image.
You can activate profiles using the `-P` flag on the command line.

TIP: If you don't want to use `spring-boot-starter-parent` you'll need to configure executions for the `process-aot` goal from Spring Boot's plugin and the `add-reachability-metadata` goal from the Native Build Tools plugin.

To build the image, you can run the `spring-boot:build-image` goal with the `native` profile active:

[source,shell]
----
$ mvn -Pnative spring-boot:build-image
----



[[howto.native-image.developing-your-first-application.buildpacks.gradle]]
=== Using Gradle

The Spring Boot Gradle plugin automatically configures AOT tasks when the GraalVM Native Image plugin is applied.
You should check that your Gradle build contains a `plugins` block that includes `org.graalvm.buildtools.native`.

As long as the `org.graalvm.buildtools.native` plugin is applied, the `bootBuildImage` task will generate a native image rather than a JVM one.
You can run the task using:

[source,shell]
----
$ gradle bootBuildImage
----



[[howto.native-image.developing-your-first-application.buildpacks.running]]
=== Running the example

Once you have run the appropriate build command, a Docker image should be available.
You can start your application using `docker run`:

[source,shell]
----
$ docker run --rm -p 8080:8080 docker.io/library/myproject:0.0.1-SNAPSHOT
----

You should see output similar to the following:

[source,shell]
----
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v{version-spring-boot})
....... . . .
....... . . . (log output here)
....... . . .
........ Started MyApplication in 0.08 seconds (process running for 0.095)
----

NOTE: The startup time differs from machine to machine, but it should be much faster than a Spring Boot application running on a JVM.

If you open a web browser to `http://localhost:8080`, you should see the following output:

[source]
----
Hello World!
----

To gracefully exit the application, press `ctrl-c`.



[[howto.native-image.developing-your-first-application.native-build-tools]]
== Building a Native Image using Native Build Tools

If you want to generate a native executable directly without using Docker, you can use GraalVM Native Build Tools.
Native Build Tools are plugins shipped by GraalVM for both Maven and Gradle.
You can use them to perform a variety of GraalVM tasks, including generating a native image.



[[howto.native-image.developing-your-first-application.native-build-tools.prerequisites]]
=== Prerequisites

To build a native image using the Native Build Tools, you'll need a GraalVM distribution on your machine.
You can either download it manually on the {url-download-liberica-nik}[Liberica Native Image Kit page], or you can use a download manager like SDKMAN!.



[[howto.native-image.developing-your-first-application.native-build-tools.prerequisites.linux-macos]]
==== Linux and macOS

To install the native image compiler on macOS or Linux, we recommend using SDKMAN!.
Get SDKMAN! from https://sdkman.io and install the Liberica GraalVM distribution by using the following commands:

[source,shell,subs="verbatim,attributes"]
----
$ sdk install java {version-graal}.r17-nik
$ sdk use java {version-graal}.r17-nik
----

Verify that the correct version has been configured by checking the output of `java -version`:

[source,shell,subs="verbatim,attributes"]
----
$ java -version
openjdk version "17.0.5" 2022-10-18 LTS
OpenJDK Runtime Environment GraalVM 22.3.0 (build 17.0.5+8-LTS)
OpenJDK 64-Bit Server VM GraalVM 22.3.0 (build 17.0.5+8-LTS, mixed mode)
----



[[howto.native-image.developing-your-first-application.native-build-tools.prerequisites.windows]]
==== Windows

On Windows, follow https://medium.com/graalvm/using-graalvm-and-native-image-on-windows-10-9954dc071311[these instructions] to install either https://www.graalvm.org/downloads/[GraalVM] or {url-download-liberica-nik}[Liberica Native Image Kit] in version {version-graal}, the Visual Studio Build Tools and the Windows SDK.
Due to the https://docs.microsoft.com/en-US/troubleshoot/windows-client/shell-experience/command-line-string-limitation[Windows related command-line maximum length], make sure to use x64 Native Tools Command Prompt instead of the regular Windows command line to run Maven or Gradle plugins.



[[howto.native-image.developing-your-first-application.native-build-tools.maven]]
=== Using Maven

As with the xref:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.maven[buildpacks support], you need to make sure that you're using `spring-boot-starter-parent` in order to inherit the `native` profile and that the `org.graalvm.buildtools:native-maven-plugin` plugin is used.

With the `native` profile active, you can invoke the `native:compile` goal to trigger `native-image` compilation:

[source,shell]
----
$ mvn -Pnative native:compile
----

The native image executable can be found in the `target` directory.



[[howto.native-image.developing-your-first-application.native-build-tools.gradle]]
=== Using Gradle

When the Native Build Tools Gradle plugin is applied to your project, the Spring Boot Gradle plugin will automatically trigger the Spring AOT engine.
Task dependencies are automatically configured, so you can just run the standard `nativeCompile` task to generate a native image:

[source,shell]
----
$ gradle nativeCompile
----

The native image executable can be found in the `build/native/nativeCompile` directory.



[[howto.native-image.developing-your-first-application.native-build-tools.running]]
=== Running the Example

At this point, your application should work. You can now start the application by running it directly:

[tabs]
======
Maven::
+
[source,shell]
----
$ target/myproject
----
Gradle::
+
[source,shell]
----
$ build/native/nativeCompile/myproject
----
======

You should see output similar to the following:

[source,shell,subs="verbatim,attributes"]
----
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::  (v{version-spring-boot})
....... . . .
....... . . . (log output here)
....... . . .
........ Started MyApplication in 0.08 seconds (process running for 0.095)
----

NOTE: The startup time differs from machine to machine, but it should be much faster than a Spring Boot application running on a JVM.

If you open a web browser to `http://localhost:8080`, you should see the following output:

[source]
----
Hello World!
----

To gracefully exit the application, press `ctrl-c`.
