Publishing Single-File Apps
Publishing with dotnet publish -p:PublishSingleFile=true -r linux-x64 bundles your application's managed assemblies (and optionally native dependencies) into a single native executable for a specific RID, rather than producing a folder full of loose DLLs. This dramatically simplifies distribution, copying or shipping one file instead of managing a directory of dozens of dependency assemblies, and is commonly paired with a self-contained publish so the target machine needs nothing but that one file to run the app.
Cricket analogy: A touring squad checking in for a series with all kit consolidated into one oversized team trunk instead of forty individual bags simplifies logistics at every airport, similar to dotnet publish -p:PublishSingleFile=true bundling an app and its dependencies into one executable instead of a folder full of DLLs.
Extraction at Startup and Self-Contained vs Framework-Dependent
By default, a single-file app still extracts its bundled managed assemblies to a temporary directory on disk the first time (or every time, depending on caching settings) it runs, because the .NET runtime needs actual files on disk to memory-map and load; the 'single file' is really a self-extracting bundle format, not literal in-memory execution of everything without ever touching disk. Setting IncludeNativeLibrariesForSelfExtract controls whether native (non-managed) dependencies are also embedded and extracted, and self-contained single-file publishes differ from framework-dependent ones in that the former embeds the runtime itself while the latter still expects a compatible shared runtime already installed on the machine.
Cricket analogy: A team's equipment truck unpacks gear into designated zones at the stadium before the match can start, adding setup time before play begins, similar to a single-file app extracting its bundled DLLs to a temp directory before the process can actually run.
Combining Single-File with Trimming
Combining PublishTrimmed with single-file publishing reduces the final executable's size further by statically analyzing which code is actually reachable and removing everything else, which matters a lot for a bundle that's already carrying the whole runtime. This comes with real risk: trimming can't always prove that reflection-based code paths are reachable, so heavily reflection-driven libraries (some ORMs, some serializers, dependency injection containers using runtime type scanning) can break silently unless properly annotated or tested against the trimmed output; IncludeAllContentForSelfExtract additionally controls whether non-assembly content files get bundled into the single file too.
Cricket analogy: A touring squad trims its traveling party down to only essential players and support staff to reduce costs and logistics for a short white-ball series, similar to PublishTrimmed stripping unused code from a single-file .NET app to reduce its final size, at the risk of cutting something needed via reflection.
dotnet publish -c Release -r linux-x64 --self-contained \
-p:PublishSingleFile=true \
-p:IncludeNativeLibrariesForSelfExtract=true \
-p:PublishTrimmed=true
# csproj equivalent
# <PropertyGroup>
# <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
# <SelfContained>true</SelfContained>
# <PublishSingleFile>true</PublishSingleFile>
# <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
# </PropertyGroup>Platform Caveats and What 'Single File' Really Means
Despite the name, a single-file publish doesn't always produce literally one file: debug symbols (.pdb) are excluded from the bundle by default, and depending on IncludeNativeLibrariesForSelfExtract and platform, some native libraries may still be deployed alongside the executable rather than embedded inside it. Behavior also differs meaningfully between Windows and Linux around how native dependencies are handled, and single-file publishing has historically had specific interactions and restrictions with ReadyToRun compilation that are worth checking against the current SDK's release notes before assuming a given combination of publish flags is supported.
Cricket analogy: Even a 'complete' touring squad still needs local ground staff and umpires provided by the host board that don't travel with the team, similar to how a 'single-file' .NET publish can still leave the .pdb debug symbols or certain native libraries as separate files unless explicitly configured otherwise.
You can control where a self-extracting single-file app unpacks its temporary files by setting the DOTNET_BUNDLE_EXTRACT_BASE_DIR environment variable, useful in locked-down container environments where the default temp path isn't writable, or when you want extracted files cleaned up from a predictable location.
Some antivirus and endpoint-protection software flags self-extracting single-file .NET executables as suspicious purely because of the self-extraction behavior, and the extraction step itself adds measurable cold-start overhead compared to a plain framework-dependent folder deployment. Benchmark this trade-off before assuming single-file publishing is a pure win for latency-sensitive workloads.
- PublishSingleFile bundles an app's managed assemblies into one executable for a specific RID.
- Single-file apps are typically self-extracting bundles; they still write files to a temp directory at startup by default.
- IncludeNativeLibrariesForSelfExtract controls whether native dependencies are embedded in the bundle or left alongside it.
- Self-contained single-file publishes embed the runtime itself; framework-dependent ones still need a compatible shared runtime installed.
- Combining PublishTrimmed with single-file reduces size but risks breaking reflection-heavy dependencies.
- Debug symbols (.pdb) are excluded from the single file by default even though the executable looks self-contained.
- DOTNET_BUNDLE_EXTRACT_BASE_DIR controls where a self-extracting app unpacks itself, useful for locked-down containers.
Practice what you learned
1. What actually happens at startup for a typical self-extracting single-file .NET app?
2. What does IncludeNativeLibrariesForSelfExtract control?
3. Why is combining PublishTrimmed with single-file publishing risky for some libraries?
4. Which file type is typically excluded from a single-file publish by default?
5. What is the purpose of the DOTNET_BUNDLE_EXTRACT_BASE_DIR environment variable?
Was this page helpful?
You May Also Like
Runtime Identifiers and Native AOT
How Runtime Identifiers (RIDs) target specific platforms and how Native AOT compiles .NET apps straight to native code for fast, lightweight startup.
.NET on Linux and macOS
How the .NET SDK and runtime install, behave, and get deployed across Linux and macOS, and the platform differences that matter for portable code.
dotnet watch and Hot Reload
How dotnet watch automatically rebuilds your app on file changes, and how Hot Reload patches a running process live to speed up the edit-test loop.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics