Skip to content

/flags/dotnet-cli/dotnet-publish-single-file

dotnet publish -p:PublishSingleFile=true: publish one executable file

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · 10.0.401updated
tool
.NET CLI
command
dotnet publish
flag
-p:PublishSingleFile=true
default
false (the app is published as many files)

dotnet publish -r linux-x64 -p:PublishSingleFile=true bundles the application and its managed dependencies into one executable next to (optionally) a .pdb. It is an MSBuild property rather than a dedicated CLI option, so it is passed with -p: and can also live in the project file. The bundle is built for one runtime identifier (RID), so pass -r; add --self-contained to bundle the .NET runtime too, so the file runs on machines without .NET.

Normal and single-file publish

bash
dotnet new console -o app > /dev/null && cd app
dotnet publish -r linux-x64 -o multi -v q -nologo > /dev/null 2>&1
dotnet publish -r linux-x64 -p:PublishSingleFile=true -o single -v q -nologo > /dev/null 2>&1
echo "--- normal"
ls multi
echo "--- PublishSingleFile=true"
ls single

Output

--- normal
app
app.deps.json
app.dll
app.pdb
app.runtimeconfig.json
--- PublishSingleFile=true
app
app.pdb

The normal publish writes app.dll, the launcher, the dependency manifest and the runtime configuration; the single-file publish leaves only the executable and its symbols. app is the Linux launcher with the application bundled inside; on Windows targets it is app.exe.

Property or optionEffect
-p:PublishSingleFile=trueBundle the app into one executable for the given RID
--self-containedInclude the .NET runtime in the bundle
-p:IncludeNativeLibrariesForSelfExtract=trueAlso bundle native libraries (extracted at start-up)
-p:EnableCompressionInSingleFile=trueCompress bundled assemblies (self-contained only)
-p:DebugType=embeddedEmbed symbols so no .pdb is written next to the file
-p:PublishTrimmed=trueTrim unused code to shrink self-contained bundles

In the project file

xml
<PropertyGroup>
  <PublishSingleFile>true</PublishSingleFile>
  <SelfContained>true</SelfContained>
  <RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>

With these properties a plain dotnet publish produces the single file. Keep them in a separate publish profile (Properties/PublishProfiles/*.pubxml) if developers should not get them on every publish.

Pitfalls

  • Assembly.Location and Assembly.GetFile return empty values inside a bundle; code that builds paths from them breaks. The SDK warns about such calls (IL3000) during publish.
  • Native libraries (SQLite, image codecs) stay next to the executable unless IncludeNativeLibrariesForSelfExtract is set, so the output may still be more than one file.
  • A framework-dependent single file still needs the right runtime installed; for a truly standalone file combine it with --self-contained.
  • The file is built for one RID; publish separately for Windows, Linux and macOS.

FAQ

Why does PublishSingleFile require a runtime identifier?

The single file is a native executable (apphost) for one operating system and CPU, with the app bundled inside. Older SDKs refused to publish a single file without -r; the .NET 10 SDK falls back to the RID of the machine running the build, which is rarely the server you deploy to. Always pass -r explicitly.

Why is Assembly.Location empty in a single-file app?

Assemblies are loaded from inside the bundle, not from files, so Assembly.Location returns an empty string. Use AppContext.BaseDirectory for the folder of the executable.

Is the single file self-contained?

Only if you also pass --self-contained. Otherwise it is a framework-dependent single file that still needs the .NET runtime installed on the target machine.

Sources