Skip to main content

Create a Trimmed Self-Contained Single Executable in .NET Core 3.0

A self-contained app is a great way to share your application as all components, runtime, and framework are included with the application. All you have to provide is the application .exe file without worrying about the presence of framework or runtime installation status on other machines. .NET Core 3.0 Preview 6 is out and there are a lot more new features. One of the useful feature is the introduction of PublishTrimmed flag. This flag reduces the size of the executable to a great extent and create a trimmed self-contained single executable in .NET Core 3.0.

Create a Trimmed Self-Contained Single Executable in .NET Core 3.0

Today with .NET Core, you can create a self-contained application using the following command.

dotnet publish -r win-x64 -c Release --self-contained

The above command builds the app in release mode and publishes the self-contained app. This will create a folder with the application .exe and other dependencies. So to run this app on another machine, you have to copy the complete folder and run the .exe from there. This is good, but there are more than 100 files and the size is also huge for a simple .NET Core based console application.

Create a Trimmed Self-Contained Single Executable in .NET Core 3.0

This problem is resolved in .NET Core 3.0 Preview 5. This release introduces a flag called PublishSingleFile which produces a single .exe file. The command can be used in the following way,

dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true

OR, you can also specify in the project file.

<PropertyGroup>
  <OutputType>Exe</OutputType>
  <TargetFramework>netcoreapp3.0</TargetFramework>
  <RootNamespace>Hello_.NETCore3</RootNamespace>
  <PublishSingleFile>true</PublishSingleFile>
  <RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>

The PublishSingleFile flag produces the following output. As you can see from the below image, there is only a single .exe file now.

Create a Trimmed Self-Contained Single Executable in .NET Core 3.0

A single .exe now, but the size is still an issue. It is near to 70 MB. This is solved in Preview 6 of .NET Core 3.0 with the introduction of a new flag called PublishTrimmed which doesn’t include DLL’s that aren’t used to reduced the size. You need to use both the flags together to create a Trimmed Self-Contained Single Executable in .NET Core 3.0. Like,

dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true

OR, you can also specify both the flags in the project file.

<PropertyGroup>
  <OutputType>Exe</OutputType>
  <TargetFramework>netcoreapp3.0</TargetFramework>
  <RootNamespace>Hello_.NETCore3</RootNamespace>
  <PublishSingleFile>true</PublishSingleFile>
  <PublishTrimmed>true</PublishTrimmed>
  <RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>

And the result is just a 29 MB single EXE. You should be saying that it is still quite big for a simple console application. But remember, it’s a self-contained application which includes the .NET Core runtime also.

Create a Trimmed Self-Contained Single Executable in .NET Core 3.0

That’s it.

Thank you for reading. Keep visiting this blog and share this in your network. Please put your thoughts and feedback in the comments section.

PS: If you found this content valuable and want to return the favour, then Buy Me A Coffee

27 thoughts to “Create a Trimmed Self-Contained Single Executable in .NET Core 3.0”

  1. When I publish my .Net Core 3.0 into a single executable, sure enough it created 1 .exe and 1.pdb only. But when I ran the .exe program for the first time, behind the scene it produces a lot of dll files plus the app dll file and config files in a randomly generated folder under C:\Users\\AppData\Local\Temp\.net folder. For example, the folder name was cjewg3k0.ack. And then, when I publish again, and run the .exe for the first time, it would produce another random folder. Is this the way it should be?

    Now when I publish with dll option, the .exe is much smaller, but then there is the app .dll, dll.config, json, and reference dlls in the publish folder. The good news is, this one does not create a random folder like the single-executable does.

  2. Great article.

    I tried using do this using preview 7, but it doesn’t work as I expect. I’ve tried both using the CLI flag and setting it in the “fsproj” file (it’s a F# project). No matter what I do it publishes everything and I don’t get the single file I expected.

    I have this in my fsproj

    true
    true

  3. The important thing to remember about this feature, is that it allows for some flexibility. If this was the ideal solution for every build, it would not be a feature, and would be the default build option. This particular feature is important, as it allows a developer to build with the latest in netcore advancements, and not have to target older frameworks just because a client is unwilling to install the runtimes on a particular server. This is something I have encountered on more than one occassion, and it has kept me developing with older frameworks, which I did not like. As with most things, there are pro’s and con’s, and they would of course have to be discussed with the client. Most clients I know, would objectively favor (and would be quite excited about) not needing to install more runtimes, having only a single self-contained executable to keep track of, and all while minimizing/negating installation procedures due to the inherent portability. These are pain points for the client I’m currently working with, so this is an incredible addition to the framework. I do hope this feature gets optimized/streamlined and it becomes possible to create a self-contained executable that does not include anything beyond only what is used of the framework (to minimize its size as much as possible). This is an incredible start though!

    Thank you for the information!

  4. What’s the minimum size of a “Hello World!” self-contained console executable with .NET Core 3 preview 6?

      1. Then that should be the benchmark for future updates since compared to a native C++ (or even a D) app, a trivial program like “Hello World!” gets way higher right now.

        1. yes, it’ a amazing hello world in just 29MB, nothing can touch it, everyone should port there hello worlds to this fabulous Core technology !!

    1. It depends, imho. Simply using a bare OS image definitely would work but you’d totally miss layer caching.

  5. I alwasy looked at this ‘self-contained’ solution as a desperate workaroud when a developer gets confused of the plethora of incompatible OS, .dll versions, frameworks, etc.
    All this just try to evade the real backlog the .NET infrastructure has: the lack for a clear, transparent and unified development and running environment.

    1. I don’t agree with your sentiment. How is this a ‘workaround’? .Net was written to run in a Windows environment. The original framework contains all the required operating system translation. The environment is the IL, and Windows runs the IL natively.

      This solution is very close to Java, but java requires you to install the JRE to execute java applications.

      They took the “core” of c#, removing all the unnecessary OS bits and created a portable language.

      It isn’t about “develipers getting confused” but abstraction and portability. You COULD write everything in c++ but it’s a rather dated language for higher level programming

      1. I was trying to use it with WPF, but there were errors during build and when I fixed them, I had a problem with running the app.

    1. I think the idea would be that it doesn’t increase more once you build real world / LOB apps with it, given the cost will mainly be including the framework

      1. After a dozen or so of these (Or hundreds / thousands as would generally be the case), it’d be smaller just to have the .NET Framework installed in the first place…

Leave a Reply

Your email address will not be published. Required fields are marked *