Publish .NET apps with the .NET CLI

This article demonstrates how you can publish your .NET application from the command line. .NET provides three ways to publish your applications. Framework-dependent deployment produces a cross-platform .dll file that uses the locally installed .NET runtime. Framework-dependent executable produces a platform-specific executable that uses the locally installed .NET runtime. Self-contained executable produces a platform-specific executable and includes a local copy of the .NET runtime.

For an overview of these publishing modes, see .NET Application Deployment.

Looking for some quick help on using the CLI? The following table shows some examples of how to publish your app. You can specify the target framework with the -f <TFM> parameter or by editing the project file. For more information, see Publishing basics.

Publish Mode Command
Framework-dependent deployment dotnet publish -c Release -p:UseAppHost=false
Framework-dependent executable dotnet publish -c Release -r <RID> --self-contained false
dotnet publish -c Release
Self-contained deployment dotnet publish -c Release -r <RID> --self-contained true

Note

  • The -c Release parameter isn't required. It's provided as a reminder to publish the Release build of your app.
  • In .NET SDK 3.1 or higher, framework-dependent executable is the default publishing mode when running the basic dotnet publish command.

Publishing basics

The <TargetFramework> setting of the project file specifies the default target framework when you publish your app. You can change the target framework to any valid Target Framework Moniker (TFM). For example, if your project uses <TargetFramework>net8.0</TargetFramework>, a binary that targets .NET 8 is created. The TFM specified in this setting is the default target used by the dotnet publish command.

If you want to target more than one framework, you can set the <TargetFrameworks> setting to multiple TFM values, separated by a semicolon. When you build your app, a build is produced for each target framework. However, when you publish your app, you must specify the target framework with the dotnet publish -f <TFM> command.

The default BUILD-CONFIGURATION mode is Debug unless changed with the -c parameter.

The default output directory of the dotnet publish command is ./bin/<BUILD-CONFIGURATION>/<TFM>/publish/. For example, dotnet publish -c Release -f net8.0 publishes to ./bin/Release/net8.0/publish/. However, you can opt into a simplified output path and folder structure for all build outputs. For more information, see Artifacts output layout.

Native dependencies

If your app has native dependencies, it may not run on a different operating system. For example, if your app uses the native Windows API, it won't run on macOS or Linux. You would need to provide platform-specific code and compile an executable for each platform.

Consider also, if a library you referenced has a native dependency, your app may not run on every platform. However, it's possible a NuGet package you're referencing has included platform-specific versions to handle the required native dependencies for you.

When distributing an app with native dependencies, you may need to use the dotnet publish -r <RID> switch to specify the target platform you want to publish for. For a list of runtime identifiers, see Runtime Identifier (RID) catalog.

More information about platform-specific binaries is covered in the Framework-dependent executable and Self-contained deployment sections.

Sample app

You can use the following app to explore the publishing commands. The app is created by running the following commands in your terminal:

mkdir apptest1
cd apptest1
dotnet new console
dotnet add package Figgle

The Program.cs or Program.vb file that is generated by the console template needs to be changed to the following:

using System;

namespace apptest1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Figgle.FiggleFonts.Standard.Render("Hello, World!"));
        }
    }
}
Module Program
    Sub Main(args As String())
        Console.WriteLine(Figgle.FiggleFonts.Standard.Render("Hello, World!"))
    End Sub
End Module

When you run the app (dotnet run), the following output is displayed:

  _   _      _ _         __        __         _     _ _
 | | | | ___| | | ___    \ \      / /__  _ __| | __| | |
 | |_| |/ _ \ | |/ _ \    \ \ /\ / / _ \| '__| |/ _` | |
 |  _  |  __/ | | (_) |    \ V  V / (_) | |  | | (_| |_|
 |_| |_|\___|_|_|\___( )    \_/\_/ \___/|_|  |_|\__,_(_)
                     |/

Framework-dependent deployment

When you publish your app as an FDD, a <PROJECT-NAME>.dll file is created in the ./bin/<BUILD-CONFIGURATION>/<TFM>/publish/ folder. To run your app, navigate to the output folder and use the dotnet <PROJECT-NAME>.dll command.

Your app is configured to target a specific version of .NET. That targeted .NET runtime is required to be on any machine where your app runs. For example, if your app targets .NET Core 8, any machine that your app runs on must have the .NET Core 8 runtime installed. As stated in the Publishing basics section, you can edit your project file to change the default target framework or to target more than one framework.

Publishing an FDD creates an app that automatically rolls-forward to the latest .NET security patch available on the system that runs the app. For more information on version binding at compile time, see Select the .NET version to use.

Publish Mode Command
Framework-dependent deployment dotnet publish -c Release -p:UseAppHost=false

Framework-dependent executable

Framework-dependent executable (FDE) is the default mode for the basic dotnet publish command. You don't need to specify any other parameters, as long as you want to target the current operating system.

In this mode, a platform-specific executable host is created to host your cross-platform app. This mode is similar to FDD, as FDD requires a host in the form of the dotnet command. The host executable filename varies per platform and is named something similar to <PROJECT-FILE>.exe. You can run this executable directly instead of calling dotnet <PROJECT-FILE>.dll, which is still an acceptable way to run the app.

Your app is configured to target a specific version of .NET. That targeted .NET runtime is required to be on any machine where your app runs. For example, if your app targets .NET 8, any machine that your app runs on must have the .NET 8 runtime installed. As stated in the Publishing basics section, you can edit your project file to change the default target framework or to target more than one framework.

Publishing an FDE creates an app that automatically rolls-forward to the latest .NET security patch available on the system that runs the app. For more information on version binding at compile time, see Select the .NET version to use.

Publish Mode Command
Framework-dependent executable dotnet publish -c Release -r <RID> --self-contained false
dotnet publish -c Release

Whenever you use the -r switch, the output folder path changes to: ./bin/<BUILD-CONFIGURATION>/<TFM>/<RID>/publish/

If you use the example app, run dotnet publish -f net6.0 -r win-x64 --self-contained false. This command creates the following executable: ./bin/Debug/net6.0/win-x64/publish/apptest1.exe

Note

You can reduce the total size of your deployment by enabling globalization invariant mode. This mode is useful for applications that are not globally aware and that can use the formatting conventions, casing conventions, and string comparison and sort order of the invariant culture. For more information about globalization invariant mode and how to enable it, see .NET Globalization Invariant Mode.

Self-contained deployment

When you publish a self-contained deployment (SCD), the .NET SDK creates a platform-specific executable. Publishing an SCD includes all required .NET files to run your app but it doesn't include the native dependencies of .NET (for example, for .NET 6 on Linux or .NET 8 on Linux). These dependencies must be present on the system before the app runs.

Publishing an SCD creates an app that doesn't roll forward to the latest available .NET security patch. For more information on version binding at compile time, see Select the .NET version to use.

You must use the following switches with the dotnet publish command to publish an SCD:

  • -r <RID>

    This switch uses an identifier (RID) to specify the target platform. For a list of runtime identifiers, see Runtime Identifier (RID) catalog.

  • --self-contained true

    This switch tells the .NET SDK to create an executable as an SCD.

Publish Mode Command
Self-contained deployment dotnet publish -c Release -r <RID> --self-contained true

Tip

  • In .NET 6 and later versions, you can reduce the total size of compatible self-contained apps by publishing trimmed. This enables the trimmer to remove parts of the framework and referenced assemblies that are not on any code path or potentially referenced in runtime reflection. See trimming incompatibilities to determine if trimming makes sense for your application.
  • You can reduce the total size of your deployment by enabling globalization invariant mode. This mode is useful for applications that are not globally aware and that can use the formatting conventions, casing conventions, and string comparison and sort order of the invariant culture. For more information about globalization invariant mode and how to enable it, see .NET Core Globalization Invariant Mode.

See also