Native AOT compilation in ASP.NET Core produces a single executable with no runtime JIT and no separate .NET installation requirement. The resulting binary is smaller, starts in milliseconds, and fits cloud container constraints more easily than a standard publish.

The feature has matured across recent releases. Developers targeting Linux containers or Windows services can now move production workloads to AOT with acceptable trade-offs around reflection and dynamic loading.

#When Native AOT is the right choice

Choose Native AOT when startup latency or image size dominates requirements. API services behind load balancers, serverless functions, and edge containers benefit most. Applications that rely heavily on runtime code generation or late-bound assemblies should remain on the JIT path.

#Project file changes

Add the PublishAot property and remove incompatible packages. The following minimal csproj enables AOT for an ASP.NET Core Web API targeting .NET 10.

xml
<PropertyGroup>
  <TargetFramework>net10.0</TargetFramework>
  <PublishAot>true</PublishAot>
  <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

#Code adjustments required

  • Replace dynamic JSON serialization with source-generated contracts using JsonSerializerContext.
  • Register all services at build time; avoid Activator.CreateInstance for types unknown at compile time.
  • Remove or conditionally compile packages that emit IL at runtime, such as certain ORMs or plugin loaders.
csharp
[JsonSerializable(typeof(WeatherForecast))]
[JsonSerializable(typeof(List<WeatherForecast>))]
public partial class AppJsonContext : JsonSerializerContext { }

#Deployment and observability

Publish with dotnet publish -c Release -r linux-x64. The output folder contains a single executable plus any required native assets. Enable EventPipe or dotnet-trace support via the NativeAOT diagnostics package when additional telemetry is needed.

Test thoroughly with your actual traffic patterns. Measure cold-start time, working set, and any reflection-dependent libraries before committing to production.

Start with a non-critical service, enable PublishAot, address the compile-time errors, and compare published size and startup latency against the JIT version. This incremental approach reveals the real constraints of your codebase without risking core systems.