- Startup time < 1.5 seconds (vs ~4-5 seconds with JVM)
- Lower memory footprint (~50-100 MB vs ~200-300 MB)
- No JVM required - single binary distribution
- Optimal for AI agents - instant response times
Benefits of Native Compilation
Lightning Fast Startup
Native images start in under 1.5 seconds, perfect for on-demand AI agent workflows.
Low Memory Usage
Reduced memory footprint compared to JVM, ideal for running alongside resource-intensive LLMs.
Single Binary
No JVM installation needed - distribute a single executable file.
Instant Tool Execution
Minimal overhead for MCP clients to start and execute tools.
Prerequisites
Install GraalVM 21
Download and install GraalVM 21 from graalvm.org:
Set JAVA_HOME
Configure your shell to use GraalVM:Add these lines to
~/.bashrc or ~/.zshrc to persist.Building the Native Image
Run Native Compilation
Use the Maven native profile to compile:The build process will:
- Analyze all reachable code
- Perform ahead-of-time compilation
- Generate reflection and resource metadata
- Create a standalone executable
GraalVM Compatibility Requirements
HandsAI is carefully designed to be GraalVM-compatible. When contributing code, follow these rules:Reflection Registration
GraalVM uses a “closed-world assumption” - all classes must be known at compile time. Dynamic reflection requires explicit registration. HandsAI registers necessary classes insrc/main/java/org/dynamcorp/handsaiv2/config/NativeHintsConfig.java:
NativeHintsConfig.java
If you add features that use reflection, Jackson mixins, or dynamic class loading, you must register those classes in
NativeHintsConfig.java.Resource Loading
Dynamic resources (JSON files, templates, etc.) must also be registered:Avoid Runtime Classpath Scanning
GraalVM cannot dynamically scan the classpath. Instead:- ✅ Use explicit
@ComponentScanwith specific packages - ✅ Register beans explicitly in
@Configurationclasses - ❌ Avoid runtime package scanning or dynamic bean discovery
Testing Native Compatibility
After making architectural changes, always test native compilation:Distribution
Create a Distributable Binary
Running on Another Machine
Troubleshooting
ClassNotFoundException during native compilation
ClassNotFoundException during native compilation
The class is accessed via reflection but not registered. Add it to
NativeHintsConfig.java:Resource not found at runtime
Resource not found at runtime
Register the resource pattern in
NativeHintsConfig.java:Native compilation fails with out of memory
Native compilation fails with out of memory
Increase Maven memory:
Slower startup than expected
Slower startup than expected
Ensure you’re running the native binary, not the JAR:
Jasypt encryption not working in native image
Jasypt encryption not working in native image
Verify
NativeHintsConfig includes Jasypt classes:Performance Comparison
| Metric | JVM Mode | Native Image |
|---|---|---|
| Startup Time | ~4-5 seconds | < 1.5 seconds |
| Memory Usage | ~200-300 MB | ~50-100 MB |
| Build Time | ~30 seconds | ~5-10 minutes |
| Binary Size | ~60 MB (JAR) | ~100 MB (native) |
| Distribution | Requires JVM | Standalone |
What’s Next?
Configuration
Optimize settings for production deployment
Bridge Setup
Connect the native binary to MCP clients