Native AOT
Run `dotnet publish -r linux-x64` two ways on one console app and the output folders disagree: one drops a single file you can execute, the other a `MyApp.dll` that still needs translating into machine code as it runs.
- ▸Ship a program with no compiler inside it and one .NET Lambda's billed time dropped 91%.
- ▸The same rule that deletes code you never reach is what makes a reflection call crash at run time.
- ▸Freeze every reachable method at build and the compiler proves a type is never subclassed, making its virtual calls direct.
Take an ordinary console app and publish it for one specific machine:
dotnet publish -r linux-x64 -c Release
Now add a single line to the .csproj and publish the exact same project again:
<PropertyGroup> <PublishAot>true</PublishAot> </PropertyGroup>
The two publish folders do not look alike. The first holds MyApp.dll, a MyApp.runtimeconfig.json, and a folder of supporting .dlls. You can open that .dll in a disassembler and read the instruction-level contents the build emitted, the shipped-instructions-are-not-machine-code point from the previous topic, and at run time something still has to translate those instructions before the CPU executes them.
The second folder holds essentially one thing: a single native executable you run directly. There is no MyApp.dll beside it, and nothing inside it disassembles back to your method bodies. Same source, same dotnet publish, two different kinds of artifact. The first ships your program as instructions to be translated while it runs; the second ships it already as machine code, with the translating compiler removed from the picture. The rest of this topic is what that second folder had to give up to be that small and that immediate.