Select Page

A C# program can reach the CPU through JIT compilation at execution time or through Native AOT compilation during publishing. The useful choice depends on the application: how it loads code, which libraries it uses, where it runs, and how you will maintain it.

Technical verification: 4 October 2026. Examples target .NET 10 and were checked with SDK 10.0.401 on Linux x64. Platform-specific deployment and package compatibility must be checked for your target environment.

Separate the language compiler from the runtime

The C# compiler translates source into intermediate language (IL) and metadata. In the usual modern .NET execution path, CoreCLR loads the application, provides services such as garbage collection and exceptions, and uses a JIT compiler to generate machine code. Roslyn is the compiler infrastructure; it is not the runtime. See Microsoft’s managed execution explanation for IL and metadata.

This separation explains why changing C# syntax does not automatically change deployment. A record or async method still needs an appropriate compiler, target framework, libraries, and execution environment. Platform-specific dependencies remain platform-specific even when the application is written in C#.

Compare deployment choices

Choice What the target needs What to verify
Framework-dependent A compatible installed .NET runtime Runtime selection, patch policy, and native dependencies
Self-contained, usual JIT path The included runtime and target OS dependencies RID, bundled runtime servicing, complete publish folder
Native AOT Native application and target OS dependencies AOT/trimming compatibility, RID, toolchain, deployed binary behavior

A self-contained application does not automatically use Native AOT. Likewise, a single-file executable is a packaging choice, not proof that the program has no JIT. Microsoft’s publishing overview distinguishes these settings.

Run one CLI through both execution paths

Install the .NET 10 SDK and create a project:

dotnet new console --framework net10.0 --name RuntimeDemo
cd RuntimeDemo

Replace Program.cs with this complete program:

using System;
using System.Globalization;

if (args.Length != 1 || !int.TryParse(args[0], NumberStyles.Integer,
    CultureInfo.InvariantCulture, out int number))
{
    Console.Error.WriteLine("Usage: RuntimeDemo <integer>");
    return 2;
}
Console.WriteLine($"input={number}");
try
{
    Console.WriteLine($"square={checked(number * number)}");
    return 0;
}
catch (OverflowException)
{
    Console.Error.WriteLine("The square is outside the int range.");
    return 3;
}

Run dotnet run -- 12. The output is:

input=12
square=144

The exit code is zero. A missing or invalid integer prints usage to standard error and returns 2. An input of 50,000 prints its input, reports overflow to standard error, and returns 3. These cases make the example useful for deployment checks: a binary that only starts successfully has not yet demonstrated equivalent error behavior.

Publish and check the Native AOT result

Native AOT compiles the application’s IL to native code during publishing and does not use a JIT at runtime. It still supplies managed-runtime services. Review the official Native AOT prerequisites and limitations; a Linux publish requires a native compiler/linker and development libraries.

Add <PublishAot>true</PublishAot> inside the project’s PropertyGroup, then publish on the target operating-system family:

dotnet publish -c Release -r linux-x64 -o publish-aot
./publish-aot/RuntimeDemo 12

This article’s Linux verification used the existing GCC toolchain via -p:CppCompilerAndLinker=gcc. The native ELF executable produced the same stdout, stderr, and exit codes as the managed program for valid, invalid, and overflow inputs. That is a correctness result; this exercise did not measure startup time, memory, or throughput.

For Windows or macOS, follow their documented prerequisites and choose the corresponding RID. Native AOT does not support cross-OS compilation; publish on the target OS. Some cross-architecture builds are supported with additional prerequisites. A successful Linux x64 build does not verify a Windows, ARM, or older-Linux deployment.

Handle compatibility before optimizing

Native AOT places limits on runtime code generation and dynamic assembly loading, and requires trimming. Reflection needs the metadata its execution paths use. Treat AOT and trimming warnings as compatibility work: identify the calling package or API, choose a supported alternative or explicit metadata strategy, and test the actual published application.

In a long-running JIT application, tiered compilation can change the code used as execution progresses; dynamic PGO can use observed execution patterns. These mechanisms are described in the runtime compilation settings. A comparison should therefore record cold startup separately from steady-state work, use equivalent inputs, include deployment size, and keep logs and measurement methodology. This sample supplies no universal performance winner.

Where bflat fits

bflat combines Roslyn and a NativeAOT-based compiler/runtime with its own tooling. Its documented DotNet and Zero standard-library modes have different capabilities; Zero is a minimal library and cannot be assumed to run normal .NET application code.

The official latest-release API returned v8.0.2, published 29 February 2024, when checked for this article. Pin the actual release you evaluate and inspect its supported targets, runtime provenance, dependency workflow, and license. The SDK 10 tests here do not certify bflat compatibility or C# 14 support in that release. This article does not present a bflat benchmark or a tested bflat build.

Choose a reversible next step

Keep a known-good normal publish, add the AOT experiment in a separate output folder, run the same correctness fixtures against both, and retain both deployment artifacts until the trial is complete. Start with a small CLI before changing the deployment of a large application.

If the program is unfamiliar, work through Lesson 1’s console setup. Parse and arithmetic details are covered in string-to-int conversion and integer arithmetic.

Follow the C# learning roadmap to choose your next topic. For a guided explanation with an original practice task, explore the C# video tutorial collection.

Share This