Skip to content

/flags/dotnet-cli/dotnet-publish-self-contained

dotnet publish -r linux-x64 --self-contained: include the .NET runtime in the app

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · 10.0.401updated
tool
.NET CLI
command
dotnet publish
flag
-r, --runtime RID; --self-contained [true|false]; --sc; --no-self-contained
default
framework-dependent (the target machine needs the .NET runtime)

dotnet publish -r linux-x64 --self-contained produces a folder that contains your app and the .NET runtime for Linux x64, so it runs on a machine where .NET is not installed. -r (--runtime) picks the target platform with a runtime identifier (RID) such as win-x64, linux-x64, linux-arm64 or osx-arm64. Without --self-contained, the published app is framework-dependent: smaller, but it needs a matching shared runtime on the target.

Framework-dependent versus self-contained

bash
dotnet new console -o app > /dev/null && cd app
dotnet publish -r linux-x64 -o fd -v q -nologo > /dev/null 2>&1
dotnet publish -r linux-x64 --self-contained -o sc -v q -nologo > /dev/null 2>&1
for d in fd sc; do
  echo "--- $d: $(ls $d | wc -l) files"
  ls $d | grep -E "^(app|app\.dll|libcoreclr\.so|System\.Private\.CoreLib\.dll)$"
done

Output

--- fd: 5 files
app
app.dll
--- sc: 192 files
System.Private.CoreLib.dll
app
app.dll
libcoreclr.so

Both folders contain the Linux launcher app and app.dll. Only the self-contained one has the runtime itself (libcoreclr.so, System.Private.CoreLib.dll and almost 200 files in total). The SDK downloaded the Linux runtime pack from NuGet, which is why the command works on any operating system.

Options

OptionEffect
-r linux-x64Target platform (RID); creates a native launcher for it
--self-contained (--sc)Copy the .NET runtime into the output
--no-self-containedFramework-dependent; the target needs the shared runtime
-p:PublishSingleFile=trueBundle everything into one executable
-p:PublishTrimmed=trueRemove unused framework code (self-contained only)
-p:PublishAot=trueNative AOT compilation (set in the project file)
-o DIROutput folder (default bin/Release/<tfm>/<rid>/publish/)

Choosing

  • Framework-dependent for servers and containers where you control the runtime (for example the mcr.microsoft.com/dotnet/aspnet image): small deploys, security patches arrive with runtime updates.
  • Self-contained for desktop tools, customer machines and minimal containers (runtime-deps images) where no runtime is installed; you ship runtime patches yourself by republishing.
  • Single file on top of either, for one executable to copy: see dotnet publish -p:PublishSingleFile=true.

In the project file

xml
<PropertyGroup>
  <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
  <SelfContained>true</SelfContained>
</PropertyGroup>

Setting the properties once avoids long command lines; use RuntimeIdentifiers (plural) to restore for several targets.

Pitfalls

  • Since the .NET 8 SDK -r alone no longer implies self-contained; scripts written for .NET 6 that relied on that now produce framework-dependent output.
  • The output for one RID does not run on another: a linux-x64 folder fails on ARM servers. Publish once per target.
  • Self-contained apps do not receive runtime security fixes from the OS; republish after every .NET patch release.
  • Targeting a framework newer than the installed SDK fails with NETSDK1045.

FAQ

Does -r imply --self-contained?

Not any more. Since the .NET 8 SDK, specifying a runtime identifier produces a framework-dependent app for that platform; add --self-contained explicitly when you want the runtime included.

How big is a self-contained .NET app?

A hello world is roughly 70 MB on disk because the whole runtime and base libraries are copied. Trimming (-p:PublishTrimmed=true) or Native AOT reduce it a lot, at the cost of compatibility checks.

Can I build a Linux self-contained app on Windows?

Yes. The SDK downloads the runtime pack for the target RID from NuGet and copies it, so dotnet publish -r linux-x64 --self-contained works on any OS. Native AOT is the exception: it must be compiled on the target OS.

Sources