Skip to content

[SPIKE] Investigate GraalVM Native Image for native binary deployment #308

@nanotaboada

Description

@nanotaboada

Problem

Even after reducing the runtime image via jlink, Java still ships a JVM — interpreter, JIT compiler, garbage collector — that Go and Rust avoid entirely by compiling to native binaries. This structural difference means Java will always be heavier than Go and Rust at runtime, regardless of JRE trimming.

Proposed Solution

Investigate whether Spring Boot's GraalVM Native Image support can produce a self-contained native binary for this application, eliminating the JVM from the runtime image entirely — similar to how Go and Rust deploy.

This is a research/spike issue, not a commitment to ship. The outcome should be a documented recommendation: proceed, defer, or reject, with justification.

Context

  • Spring Boot 4 has first-class GraalVM Native Image support via the spring-boot-starter-aot and the native build tools Maven plugin
  • GraalVM Native Image produces a platform-specific binary that starts in milliseconds with low memory footprint
  • Reflection-heavy frameworks (Spring Boot is one) require reflect-config.json hint files; Spring Boot's AOT engine generates most of these automatically, but edge cases exist
  • SQLite via JDBC with reflection-based ORM (Hibernate/Spring Data JPA) is a known friction point with native image compilation

Suggested Approach

1. Assess AOT compatibility

Run the GraalVM Native Image build locally:

./mvnw -Pnative native:compile

Document any MissingResourceConfigurationException or reflection errors.

2. Evaluate runtime image options if native build succeeds

A native binary can deploy on:

  • FROM scratch — smallest possible, no OS layer
  • FROM gcr.io/distroless/static:nonroot — includes ca-certs, non-root user
  • FROM alpine:3.23 — familiar base, adds ~8 MB, retains shell for debugging

3. Document trade-offs

Concern JVM (current) Native Image
Build time Fast Slow (~5–15 min)
Startup time ~2–5 s ~50–200 ms
Memory footprint Higher Lower
Peak throughput Higher (JIT) Lower (no JIT)
Reflection compatibility Full Requires hints
SQLite/JPA support Proven Needs validation
Image size ~100–150 MB (jlink) ~50–80 MB (estimate)

4. Acceptance criteria for proceeding

The investigation should answer:

  • Does ./mvnw -Pnative native:compile succeed without manual hint files?
  • Do all integration tests pass against the native binary?
  • Is the CI build time acceptable?
  • Does Hibernate/SQLite work correctly in native mode?

Acceptance Criteria (for this spike)

  • GraalVM Native Image build attempted and result documented
  • Compatibility issues (if any) identified and triaged
  • Before/after image size and startup time measured and recorded
  • Recommendation written: proceed / defer / reject with rationale
  • If proceeding: follow-up implementation issue filed

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    containersPull requests that update containers codeenhancementNew feature or requestgood first issueGood for newcomersjavaPull requests that update Java codeplanningEnables automatic issue planning with CodeRabbitpriority lowNice-to-have improvement. Can be deferred without blocking other work.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions