State of Native AOT in .NET 10
After 3 years since my previous article on Native AOT, let’s find out how far AOT compilation in .NET has come.
Please note that I’m not an expert. This article is purely based on my personal experience and knowledge from reading tons of blog posts, release announcements, doing personal experiments, and sneaking through the dotnet repo’s issues, pull requests, etc.
Let’s dive in.
Publish Size
First, I wanted to see the publish size, as it’s one of the main areas of focus for the .NET team. I checked the size in the last 4 versions and here’s the result:
| .NET Version | App Size (MB) | Size Reduction |
|---|---|---|
| .NET 7 | 3.65 | - |
| .NET 8 | 1.39 | -61.9% |
| .NET 9 | 1.22 | -12.2% |
| .NET 10 | 1.05 | -13.9% |
As you can see, much of the size reduction comes in .NET 8, and it has reduced even further in subsequent releases. Now, it’s sitting around 1 MB, which is really impressive.
I examined the published executable using sizoscope to see what has changed between .NET 7 & 10.

As we can see, each assembly shown here was trimmed down massively.
Enough of the “Hello World” project. Let’s move on to a real-world project.
Aspire CLI
Aspire CLI is a native CLI executable compiled using .NET Native AOT. The latest daily build is ~15 MB in size and the CLI invocation is almost instantaneous. To my knowledge, this is the first major officially supported CLI tool from Microsoft published using Native AOT, demonstrating the viability of AOT for real-world CLI scenarios. There’s more to come (dotnet CLI 👀)
Minimal API
Minimal API announced support for NativeAOT back in .NET 8. At the time, the ecosystem was not mature enough to deploy realistic workloads on NativeAOT. While I recognize that a lot of NuGet packages still lack NativeAOT support, it’s in a much more favorable position than it was a few years ago. If you’re developing and maintaining APIs that handle a large volume of traffic with strict SLA requirements, it’s worth exploring minimal APIs in AOT publish mode. This way, you can benefit from fast startup time, reduced memory usage, smaller app size.
However, note that JIT tends to achieve higher peak performance in the long run as it optimizes code at runtime. In some environments, you may trade some Requests Per Second (RPS) in AOT for deterministic startup and memory profiles. So, it’s worth running benchmarks for your own APIs and seeing how it works in your case.
AWS Lambda Functions
AWS Lambda functions have supported Native AOT since .NET 8. In their announcement blog post:
“Benchmarks show up to 86% improvement in cold start times by eliminating the JIT compilation”
Azure Functions
Azure Functions supports NativeAOT, but the functions team recommends Ready to Run (R2R) mode to mitigate the cold start problem, as they see better results.
“Although Functions does have the ability to run NativeAOT compiled apps, we have a more efficient approach for cold start mitigation that is automaitcally applied (which actually leverages a combination of NativeAOT, custom .NET hosting and other technologies). That, combined with ready-to-run, yields better results in our environment than NativeAOT.”
Avalonia UI
Avalonia, the popular cross-platform desktop framework, also now supports NativeAOT deployment.
Windows App SDK
Windows App SDK 1.6 shipped with Native AOT support. From their release notes:
“In our sample Contoso Camera app, we measured a 50% reduction in start time, an ~8x reduction in package size when using a framework package, and a ~2x reduction in package size when using Windows App SDK in self-contained mode.”
I personally tried the WinUI Gallery App, which was compiled with Native AOT. The app launched almost instantly and felt snappier.
.NET MAUI
Windows
.NET MAUI on Windows uses the Windows App SDK under the hood, and is going to get support for Native AOT publish as well. From this issue, I understand it’s going to be released slightly after .NET 10, maybe as part of servicing.
Android
Loads of work went into NativeAOT for Android in the .NET 10 release cycle and in previous releases, and it’s almost ready. Vyacheslav Volkov tested it in .NET 10 RC2 and here’s what he has to say:
“I rebuilt my test app for .NET 10 RC2 (net10.0-android, PublishAot=true) and the results are very encouraging: Galaxy Note 10+ Startup (with heavy initialization): 271–331 ms
MonoAOT comparison: 1s27-1s41ms on the same project
Everything launches and runs, and the startup speed improvement is substantial. Thank you to everyone involved for pushing this forward”
iOS & Mac Catalyst
iOS/Mac Catalyst had AOT since the beginning using Mono. iOS/Mac Catalyst now supports NativeAOT since .NET 9, whereas experimental supported was added in .NET 8.
File-based Programs
File-based programs is a new feature in .NET 10 where we can directly create and run C# (.cs) files. By default, file-based apps are published in Native AOT mode because the PublishAot flag is set to true.
Hear from Damian Edwards (PM Architect in the .NET team):
“I’m considering changing my stance to be more bold on this now and say in this new world of file-based apps we could default them to publish native AOT. Be the change you want to see and all that. We likely won’t get another chance to change a default like this for a very long time.”
This is huge because they are pushing AOT in the normal publishing flow (only for file-based programs for now). This can lead to more awareness and adoption in the community.
.NET Tools
Before .NET 10, developers were able to publish only framework-dependent dotnet tools. From .NET 10, it is now possible to ship native binaries compiled using Native AOT as a dotnet tool.
This makes the distribution of native executables easier for those who are already shipping .NET tools, and we can expect them to have faster startup times when they start using this feature.
Console/CLI Frameworks
It’s now possible to build fully AOT-compiled native CLI executables using some of these popular libraries:
Package Ecosystem
Many popular libraries have enabled support for Native AOT. Some won’t ever support it unfortunately, but alternative new packages are evolving in the ecosystem. As Native AOT adoption grows, certain patterns are becoming common to tackle the limitations:
- Using C# Incremental Generators (v2 Source Generators) instead of reflection-based approaches.
- Using C# Interceptors to intercept existing code and replace it in an AOT-friendly way.
- Using trimming annotations, which are attributes and patterns that help the linker safely remove unused code during publish.
Some of the AOT-friendly packages that I’ve come across:
- Serilog
- Kiota
- Octakit
- Sep
- SepEx
- MSTest
- StackExchange.Redis
- OpenTelemetry
- DapperAOT
- and the list goes on
Azure Packages
More Azure packages have added support for AOT. You can see from the changelog that every month there’s a mention of trimming and AOT support:
- https://azure.github.io/azure-sdk/releases/2025-05/dotnet.html
- https://azure.github.io/azure-sdk/releases/2025-07/dotnet.html
- https://azure.github.io/azure-sdk/releases/2025-08/dotnet.html
- https://azure.github.io/azure-sdk/releases/2025-09/dotnet.html
As far as I’m aware, many of the commonly used Azure SDK packages have been updated with AOT support. One exception that I know of is Microsoft.Azure.Cosmos, which may get AOT support in v4.
I came across an interesting blog post about a CLI tool azddns which uses some of the Azure SDKs, compiled and published as a Native AOT executable.
New Packages
Some of the newly announced packages come with AOT support out of the box. Here are some of them that come to mind:
- Microsoft.Extensions.OpenApi
- Microsoft.Extensions.Validation
- C# MCP SDK libraries
- Microsoft.Extensions.AI libraries
- Microsoft.Agents.AI
PowerToys
The ‘Command Palette’ utility in PowerToys started shipping in AOT compilation mode, and here’s what they say in release v0.93:
“Command Palette reduced its startup memory usage by ~15%, load time by ~40%, built-in extensions loading time by ~70%, and installation size by ~55%—all due to using the full Ahead-of-Time (AOT) compilation mode in Windows App SDK.”
Future
dotnetCLI itself as a native executable? Highly likely in the next release https://github.com/dotnet/msbuild/issues/12141- EF Core? Potentially in the future https://github.com/dotnet/efcore/issues/34446
- WinForms? Maybe in the future - https://github.com/dotnet/winforms/issues/4649
- There could be more! We’ll find out next time
Closing Thoughts
I can see a real push for Native AOT from Microsoft and growing adoption in the .NET ecosystem, which is great to see. When I see the PRs that made Native AOT possible in many of these cases, I notice that it requires deep technical understanding of the constraints and workarounds. In some cases, it won’t be possible to support at all due to the limitations.
At the end of the day, it comes down to your app and whether it works for you and you’ll benefit from it or not. In my opinion, it’s worth exploring this area if you are building CLIs, large-scale APIs, desktop or mobile applications.
If I have missed any other interesting project or if you’d like to share your personal experience in building AOT applications, please let me know in the comments.
Thanks for reading… Happy AOT’ing!