Single-file publishing has been part of .NET since version 5, but .NET 10 takes it to a new level with improved ahead-of-time (AOT) compilation, better trimming analysis, and smaller default output sizes. This tutorial walks you through publishing a real app as a single binary — no install required on the target machine.
Prerequisites
- .NET 10 SDK installed (
dotnet --versionshould show10.x.x) - A console or ASP.NET Core app to work with
Step 1: Create a new console app
dotnet new console -n SingleFileDemo
cd SingleFileDemo
Step 2: Publish as a single file
The minimal publish command for a self-contained single-file app:
dotnet publish -c Release -r linux-x64 \
--self-contained true \
-p:PublishSingleFile=true \
-o ./output
Replace linux-x64 with your target runtime identifier (win-x64, osx-arm64, etc.). The --self-contained true flag bundles the .NET runtime into the output binary.
After publishing, ./output/ contains a single executable file.
Step 3: Add trimming
Trimming removes unreachable code from the final binary, often cutting size by 60–80%:
<!-- Add to your .csproj -->
<PropertyGroup>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>full</TrimMode>
</PropertyGroup>
Then just run:
dotnet publish -c Release -r linux-x64 -o ./output
Step 4: Native AOT (optional but powerful)
For the smallest and fastest binaries, use Native AOT instead of single-file:
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
Native AOT compiles your app to native machine code at publish time. There’s no JIT at runtime, which means near-instant startup and a much smaller memory footprint.
Note: Native AOT doesn’t support all reflection patterns. Run
dotnet publishonce and review any AOT compatibility warnings before committing to this approach.
Checking binary size
ls -lh ./output/
# -rwxr-xr-x 1 user staff 12M SingleFileDemo
With trimming + AOT on a simple console app, expect 5–15 MB depending on dependencies.
Wrapping up
Single-file publishing in .NET 10 is production-ready for most workloads. Start with PublishSingleFile=true, add trimming once your app is stable, and consider Native AOT if startup time or binary size are hard constraints.
