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)
References
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
Suggested Approach
1. Assess AOT compatibility
Add to
Dotnet.Samples.AspNetCore.WebApi.csproj:Attempt a native publish:
Collect and document all AOT warnings (
ILCwarnings) and trim analysis warnings.2. Evaluate runtime image options if AOT build succeeds
FROM scratch-p:StaticLinkedRuntime=true)FROM gcr.io/distroless/static:nonrootFROM alpine:3.233. Document trade-offs
4. Acceptance criteria for proceeding
dotnet publish -c Release --self-containedwithPublishAot=truesucceed without blocking warnings?Acceptance Criteria (for this spike)
References