Publishing a Self-Contained .NET 6 Application for Runtime-Free Deployment
Produce a .NET 6 executable that runs without a pre-installed runtime using dotnet publish with a runtime identifier and self-contained flag.
14 Nov 2025, 04:35 UTC

The deployment problem self-contained publishing solves
When you deploy a standard .NET application, the target machine must already have a compatible .NET runtime installed. If the runtime is missing, outdated, or a different version is expected, the application fails to start. A self-contained deployment removes that dependency by bundling the .NET runtime, framework libraries, and native dependencies directly into your publish output. The result is a folder containing an executable that runs on a clean machine without any prior .NET installation.
This guide walks through producing that output for .NET 6 using the dotnet publish command, verifying the result, and recovering from common issues such as trimming errors or an incorrect target platform.
Desired outcome
You will have a release build of your application that includes the .NET 6 runtime and all required native libraries for a specific operating system and CPU architecture. The published folder can be copied to a target machine and executed directly, with no separate runtime installer required.
Prerequisites
- .NET 6 SDK installed. Open a terminal and run
dotnet --version. The output should begin with6.(for example,6.0.x). If it shows a different major version, either install the .NET 6 SDK or adjust the target framework accordingly. - Project targeting net6.0. Open your
.csprojfile and confirm it contains<TargetFramework>net6.0</TargetFramework>. If the project uses a different TFM, the publish output will include that runtime instead. - Known target Runtime Identifier (RID). The RID describes the target platform. Common values include
win-x64,linux-x64,linux-arm64, andosx-x64. You must know the OS and architecture of the machine where the application will run. - Sufficient disk space. A self-contained publish is significantly larger than a framework-dependent build because it includes the runtime and base class libraries. Ensure the build machine and target machine have enough free storage.
Focused procedure
1. Verify the SDK and project target
Run the following command in your terminal or command prompt to confirm the SDK version:
dotnet --info
Look for the .NET SDK entry and confirm it reports version 6.x. This is the SDK that will perform the publish. If multiple SDKs are installed, the command uses the one that matches the project's target framework by default, but verifying avoids surprises.
2. Publish with a runtime identifier
From the project root directory (the folder containing the .csproj file), run the publish command. Replace win-x64 with the RID that matches your target machine:
dotnet publish -c Release -r win-x64 --self-contained true /p:PublishTrimmed=true
What each part does:
-c Release: Builds in release mode, which applies compiler optimizations and omits debug symbols by default.-r win-x64: Specifies the Runtime Identifier. This tells the SDK to restore and publish for Windows 64-bit. Uselinux-x64for most Linux servers, or another RID as needed.--self-contained true: Includes the .NET runtime and all framework assemblies in the output. Without this flag, the publish is framework-dependent and requires the runtime to be installed on the target./p:PublishTrimmed=true: Optionally removes assemblies that the trimmer determines are unused. This reduces output size but carries risk for applications that use reflection, dynamic loading, or serialization.
By default, the output lands in bin/Release/net6.0/<rid>/publish/. You can override this with -o <path> if you want the artifacts in a specific folder.
3. Inspect the publish output
Navigate to the publish directory and list its contents. On Windows, use:
dir bin\Release\net6.0\win-x64\publish
On Linux or macOS, use:
ls bin/Release/net6.0/win-x64/publish/
You should see your application executable (for example, MyApp.exe on Windows or MyApp on Linux) alongside a much larger set of files than a framework-dependent build. Look for native runtime libraries such as hostfxr, hostpolicy, coreclr, and the base class library DLLs. Their presence confirms the runtime is bundled.
Expected checks
File inventory and size comparison
Compare the self-contained output against a framework-dependent publish to confirm the runtime is included. Run a second publish without the self-contained flag:
dotnet publish -c Release -r win-x64 --self-contained false -o bin/Release/net6.0/win-x64/framework-dep
The self-contained folder should contain substantially more files and occupy significantly more disk space. If the two folders look nearly identical, the --self-contained true flag may not have taken effect.
Clean-machine execution test
The definitive check is running the executable on a machine that does not have the .NET runtime installed. Copy the entire publish folder to the target machine and launch the executable. If the application starts and functions normally, the self-contained bundle is working. If the target machine already has a different .NET version installed, this test still validates that your bundled runtime is being used rather than the system-wide one.
SDK version confirmation
If you need to confirm exactly which SDK produced the output, run dotnet --info before publishing and note the version. This is useful when build servers have multiple SDKs installed and you need to ensure the 6.x SDK was used.
Recovery options and rollback
Publishing creates files in your project's output directory; it does not modify the system registry, install services, or alter global machine state. To roll back a publish, delete the output folder (for example, bin/Release/net6.0/win-x64/publish/). No further cleanup is required.
If trimming breaks the application
Trimming can remove types that are only discovered through reflection at runtime. Symptoms include MissingMethodException, FileNotFoundException for assemblies, or serialization failures that do not occur in untrimmed builds. To recover, republish without trimming:
dotnet publish -c Release -r win-x64 --self-contained true
If you need trimming for size but must preserve specific types, you can add trimmer descriptors to the project file or use <TrimmerRootAssembly> and related MSBuild properties. Test the trimmed output thoroughly, especially around JSON serialization, dependency injection, and any plugin or dynamic assembly loading.
If the executable fails to start on the target
A common cause is a RID mismatch. An executable published for win-x64 will not run on Linux, and a linux-x64 binary will not run on Windows. If the target OS or architecture differs, republish with the correct RID. For example, for a 64-bit ARM Linux device, use linux-arm64 instead of linux-x64.
Limitations to plan for
- Deployment size. Self-contained outputs are significantly larger than framework-dependent ones. This affects storage, download time, and container image size if you are publishing inside Docker.
- Trimming risk.
/p:PublishTrimmed=trueis not safe for every application. Reflection-heavy frameworks and libraries may lose required types. Treat trimming as an opt-in optimization that requires dedicated testing. - Platform lock-in. Each RID produces a separate artifact. If you support Windows, Linux, and macOS, you must publish three times with different RIDs.
- Runtime updates. Because the runtime is bundled, applying a .NET runtime patch means republishing and redeploying the application rather than updating a shared runtime on the host.
- Cross-OS validation. You can publish for Windows from a Linux build agent, but the final execution check should still happen on the actual target OS to catch native dependency or permission issues.
Practical result check
After publishing, confirm the folder contains your executable plus the native runtime files, then copy it to a machine without .NET installed and run it. If the application launches without a runtime error, you have a working self-contained deployment. Keep the publish command in your build scripts so the artifact can be reproduced consistently.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.