Baeldung Pro – Ops – NPI EA (cat = Baeldung on Ops)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

Partner – Orkes – NPI EA (cat=Kubernetes)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

1. Overview

In .NET development, the dotnet publish command is essential for preparing applications for distribution. It builds the application, processes its dependencies, and stores the finished distributable assets in a specific location. This tool supports a variety of deployment targets, such as folders, containers, and cloud environments.

In this tutorial, we’ll look at what dotnet publish does, how it works behind the scenes, and how to use it efficiently in various deployment circumstances.

2. What Happens During Dotnet Publish

When we run dotnet publish, the CLI executes several processes that change our source code into a production-ready package:

$ dotnet publish

In this example, when we run the command, the dotnet CLI starts converting the project to Intermediate Language (IL) assemblies. It then resolves all NuGet and project dependencies, ensuring that they work with the target framework. Following that, it moves the compiled binaries, configuration files, and static resources such as images or CSS to the publish folder.

In addition, when a runtime identifier is supplied, it contains the corresponding .NET runtime. Finally, it optimizes the files if trimming or single-file publication is selected.

3. Common Options and Flags

The dotnet publish command provides numerous arguments and MSBuild attributes for customising the output.

These options allow us to specify the build configuration, target runtime, deployment model, and even how the files are packed. We can adapt a single codebase to many contexts by mixing different flags:

$ dotnet publish -c Release -o ./deploy
Determining projects to restore...
Restored /home/user/HelloApp/HelloApp.csproj (in 110 ms).
HelloApp -> /home/user/HelloApp/bin/Release/net8.0/HelloApp.dll
HelloApp -> /home/user/HelloApp/deploy/

In this example, the -c Release flag builds with optimisations, and the -o ./deploy flag directs the published files to a deploy folder rather than the typical publish location:

Option Description
-c <CONFIGURATION> Specifies the build configuration, usually Debug or Release. Default is Debug.
-r <RUNTIME_IDENTIFIER> Targets a specific OS and architecture, e.g., win-x64, linux-arm.
–self-contained true|false Includes the .NET runtime in the output (true) or relies on the system runtime (false).
/p:PublishSingleFile=true Bundles the app and dependencies into a single executable file.
/p:PublishTrimmed=true Removes unused code from assemblies to reduce the size of the published output.
/p:PublishReadyToRun=true Precompiles assemblies to improve application startup performance.
/p:PublishAot=true Enables ahead-of-time (AOT) compilation where supported.
–no-restore Skips restoring NuGet packages before publishing.
–no-build Skips the build step and only performs publish actions (useful if the project is already built).
-o <OUTPUT_PATH> Specifies the folder where the published files should be placed.

These options allow us to fine-tune the publishing process for speed, portability, and size.

4. Framework-Dependent vs. Self-Contained

A framework-dependent deployment expects that the destination machine already has the .NET runtime installed. This keeps the published output small:

$ dotnet publish -c Release --self-contained false
HelloApp -> /home/user/HelloApp/bin/Release/net8.0/HelloApp.dll
HelloApp -> /home/user/HelloApp/bin/Release/net8.0/publish/

In this example, the publish folder contains mostly the application’s .dll file and any required libraries, but not the .NET runtime.

However, a self-contained deployment bundles the .NET runtime with the program, allowing it to execute on systems that don’t have .NET installed:

$ dotnet publish -c Release -r linux-x64 --self-contained true
HelloApp -> /home/user/HelloApp/bin/Release/net8.0/linux-x64/HelloApp.dll
HelloApp -> /home/user/HelloApp/bin/Release/net8.0/linux-x64/publish/

In this example, inspecting the publish folder displays an executable file as well as all runtime files required by that operating system and architecture.

5. Single File Publishing

Single-file publishing enables us to distribute an application, its dependencies, and, optionally, the .NET runtime as a single executable. This approach simplifies deployment by eliminating the need to handle numerous assemblies and runtime files:

$ dotnet publish -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true
HelloApp -> C:\Projects\HelloApp\bin\Release\net8.0\win-x64\HelloApp.dll
HelloApp -> C:\Projects\HelloApp\bin\Release\net8.0\win-x64\publish\

In this example, we publish a single-file executable for Windows; once published, we inspect the publish folder and find only one .exe file along with a few runtime-dependent files, depending on the parameters.

We can then proceed to launch the executable:

$ C:\Projects\HelloApp\bin\Release\net8.0\win-x64\publish\HelloApp.exe
Hello World from Single File Deployment

This indicates that the application runs correctly from a single file. Single-file publishing considerably simplifies deployment by lowering the number of files to distribute. Instead of handling multiple assemblies and runtime libraries, we can provide a single executable that can be launched immediately.

Furthermore, this method is useful in situations when simplicity and portability are important, such as distributing desktop utilities or packaging applications into containers.

6. Conclusion

In conclusion, the dotnet publish command is a crucial step in transitioning an application from development to production. It compiles the source code, handles dependencies, and generates a deployment-ready package specific to the specified environment.

In this article, we discuss what happens when we publish and how using options like –self-contained, runtime identifiers, or single-file publishing provides us fine-grained control over how programs are generated and delivered.

Finally, framework-dependent deployments reduce the footprint but rely on the presence of the .NET runtime, whereas self-contained deployments ensure portability. Single-file publishing simplifies distribution by combining everything into a single executable.