Choosing Between JIT, ReadyToRun, and Native AOT in .NET
A decision guide for .NET developers choosing between JIT, ReadyToRun, and Native AOT to balance startup speed, memory usage, and runtime flexibility.
17 Sept 2026, 11:13 UTC

The Compilation Decision
When deploying a .NET application, the primary trade-off is between startup latency and runtime flexibility. By default, .NET uses Just-In-Time (JIT) compilation, which converts Intermediate Language (IL) to machine code at runtime. While this allows for aggressive runtime optimizations, it creates a "cold start" penalty where the first few requests to a service are significantly slower.
Depending on your infrastructure—whether you are running long-lived servers, short-lived serverless functions, or memory-constrained containers—you must choose between standard JIT, ReadyToRun (R2R), or Native AOT (Ahead-of-Time).
Comparison of Deployment Modes
| Feature | Standard JIT | ReadyToRun (R2R) | Native AOT |
|---|---|---|---|
| Startup Speed | Slowest (JIT overhead) | Fast | Fastest |
| Memory Footprint | Moderate | Moderate | Lowest |
| Binary Size | Smallest | Larger | Largest (Self-contained) |
| Reflection Support | Full | Full | Highly Restricted |
| Dynamic Code | Supported (Emit) | Supported (Emit) | Not Supported |
Evaluating the Trade-offs
Standard JIT
The default behavior. It is the safest choice for complex enterprise applications that rely heavily on dynamic proxies, reflection-based serialization, or third-party libraries that generate code at runtime. Because it optimizes code based on actual usage patterns (Tiered Compilation), it can occasionally achieve higher peak throughput than pre-compiled code.
ReadyToRun (R2R)
R2R is a hybrid approach. It pre-compiles your IL into native code during the publish process but keeps the IL available. If the pre-compiled code is incompatible with the target machine's specific CPU instructions, the JIT compiler simply falls back to the IL. This reduces startup time without sacrificing the full feature set of the .NET runtime.
Native AOT
Native AOT removes the JIT compiler and the IL entirely, producing a platform-specific native binary. This is ideal for cloud-native microservices where fast scaling (cold starts) and low memory overhead are critical. However, it requires trimming—the process of removing unused code to reduce size. If your code or a library uses reflection to access a class that the trimmer thinks is unused, that class will be removed, and the app will crash at runtime.
Implementation and Validation
To test these options, you must modify your project file (.csproj) or pass flags during the dotnet publish command. These examples assume .NET 8 or later.
Configuration Examples
Run these commands from your terminal in the project root. Replace win-x64 with your target RID (e.g., linux-x64).
1. ReadyToRun (R2R)
dotnet publish -c Release -r win-x64 --self-contained <PublishReadyToRun>true</PublishReadyToRun>
2. Native AOT
dotnet publish -c Release -r win-x64 <PublishAot>true</PublishAot>
Validating AOT Compatibility
Because Native AOT failures often happen at runtime rather than compile time, you must use the AOT analyzers. Add the following to your .csproj:
<PropertyGroup>
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>
After adding this, build the project. Check the Warnings tab in your IDE or CLI output for IL2xxx or IL3xxx codes. These warnings indicate that a library you are using is not AOT-compatible (e.g., it uses Reflection.Emit).
Verification Workflow
To make a final decision, perform the following checks on your published artifacts:
- Cold Start Test: Start the application and measure the time until the first HTTP 200 response is received.
- Working Set Check: Use
dotnet-countersor Task Manager to monitor the private bytes/working set immediately after startup. - Integration Suite: Run your full suite of integration tests against the published executable, not via
dotnet run. This is the only way to catch trimming-related crashes.
Rollback Procedure
Since these changes occur at the build/publish stage and do not modify the source code logic, rolling back simply requires reverting the .csproj flags or removing the -r and <Publish...> arguments from your CI/CD pipeline and re-publishing using the default JIT settings.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.