Skip to content

[SPIKE] Investigate .NET Native AOT for native binary deployment #457

@nanotaboada

Description

@nanotaboada

Problem

Even after switching to the Alpine runtime image, .NET still ships the ASP.NET Core runtime — class libraries, JIT compiler, GC. This structural difference means .NET will be heavier than native binaries at runtime regardless of base image choice.

Proposed Solution

Investigate whether .NET 10 Native AOT can produce a self-contained native binary for this application, eliminating the runtime from the image entirely.

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

  • .NET Native AOT has been supported since .NET 7, with ASP.NET Core Minimal API support added in .NET 8. .NET 10 (current) has the most mature AOT support to date.
  • AOT produces a platform-specific native binary with no JIT, no interpreter, and no runtime installation required.
  • The application currently uses ASP.NET Core MVC controllers (not Minimal API). AOT support for MVC controllers has improved in .NET 9/10 but may still have limitations — this is the primary risk to validate.
  • EF Core has partial AOT support; SQLite + EF Core in AOT mode requires validation.
  • AutoMapper and FluentValidation use reflection; both have added AOT compatibility work but may require source generators or explicit configuration.

Suggested Approach

1. Assess AOT compatibility

Add to Dotnet.Samples.AspNetCore.WebApi.csproj:

<PublishAot>true</PublishAot>

Attempt a native publish:

dotnet publish -c Release -r linux-x64 --self-contained

Collect and document all AOT warnings (ILC warnings) and trim analysis warnings.

2. Evaluate runtime image options if AOT build succeeds

Base Size Notes
FROM scratch Smallest Requires static binary (-p:StaticLinkedRuntime=true)
FROM gcr.io/distroless/static:nonroot Small Includes ca-certs, non-root user
FROM alpine:3.23 Small Familiar; retains shell for debugging

3. Document trade-offs

Concern Runtime (current) Native AOT
Build time Fast Slow
Startup time ~1–3 s ~10–50 ms
Memory footprint Higher Lower
Peak throughput Similar (no JIT) Similar
Reflection (AutoMapper, FluentValidation) Full Requires source generators or trimming annotations
EF Core compatibility Full Partial — validate
Image size ~200–300 MB (Debian) / ~100–150 MB (Alpine) ~50–100 MB (estimate)

4. Acceptance criteria for proceeding

  • Does dotnet publish -c Release --self-contained with PublishAot=true succeed without blocking warnings?
  • Do all unit and integration tests pass against the AOT binary?
  • Is the CI build time acceptable?
  • Do AutoMapper profiles and FluentValidation validators work correctly at runtime?

Acceptance Criteria (for this spike)

  • AOT publish attempted and result documented
  • AOT/trim warnings identified and categorised (blocking vs. suppressible)
  • Compatibility issues with MVC controllers, EF Core, AutoMapper, FluentValidation assessed
  • 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

    .NETPull requests that update .NET codecontainersPull requests that update containers codeenhancementNew feature or requestgood first issueGood for newcomersplanningEnables 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