Subsystem · native

GraalVM native-image

curie native compiles your project to a standalone native binary using GraalVM's native-image tool. The result starts in milliseconds, uses a fraction of the heap, and ships without a JVM — ideal for serverless functions, CLI tools, and containers where image size and cold-start time matter.

Prerequisites

GraalVM (Community or Enterprise) must be installed and native-image must be on PATH. The easiest way is SDKMAN:

shell
$ sdk install java 21.0.3-graalce
$ native-image --version
native-image 21.0.3 2024-04-16

Configuration

Add a [native-image] table. An empty table is enough to enable the step — all keys are optional:

Curie.toml
[application]
name      = "my-cli"
version   = "0.1.0"
mainClass = "com.example.Main"

[native-image]
# Output binary name (default: application name)
outputName = "my-cli"

# Path to reachability-metadata config dir
configDir = "src/main/resources/META-INF/native-image"

# Extra flags forwarded verbatim to native-image
extraArgs = ["--no-fallback", "-H:+ReportExceptionStackTraces"]

Building

curie native compiles the project (skipping tests for a faster iteration loop) and then invokes native-image:

$ curie native --project my-cli
Building my-cli v0.1.0
  Resolve deps    3 JAR(s)
  Compile         4 source file(s)
  Package         my-cli-0.1.0.jar
  Native image    my-cli (GraalVM native-image)
  …compiling…  ~1–2 minutes…
  Done            target/my-cli

The binary lands at target/<outputName>. Run it directly — no JVM needed:

$ ./target/my-cli --help
my-cli 0.1.0
Usage: my-cli [options]

Integration with curie build

When [native-image] is present in Curie.toml, curie build also compiles the native binary after packaging the JAR and running tests. Pass --no-native to skip it when iterating quickly:

$ curie build --no-native
Building my-cli v0.1.0
  …  (native-image step skipped)
  Done            target/my-cli-0.1.0.jar

Reachability metadata

Frameworks that use reflection, dynamic proxies, or resources at runtime need GraalVM reachability metadata so the AOT compiler knows to include those classes. Place JSON configuration files in the directory declared by configDir:

The GraalVM reachability-metadata repository already contains entries for many popular libraries.