Create a Windows installer for a .NET app (WPF, WinForms, console)
Publish a .NET desktop app with dotnet publish, choose between framework-dependent and self-contained, then wrap the publish folder in a Setup.exe with shortcuts and an uninstaller.
Updated October 31, 2026 · 3 min read
Visual Studio builds your WPF or WinForms app, and dotnet publish gives you a folder that runs anywhere. The missing piece is the installer: the Start Menu entry, the Program Files folder, the uninstall entry in Windows Settings. The old ClickOnce and Visual Studio Installer Projects still exist, but both are showing their age. Here is the straightforward path from a .NET project to a Setup.exe.
Step 1: publish the app
Publishing produces a folder with everything the app needs. Run it from the project folder:
dotnet publish -c Release -r win-x64 --self-contained true
The output lands under bin\Release\net8.0-windows\win-x64\publish\ (the target framework in the path varies with your project). That folder is what you ship.
The one decision that matters:
- Self-contained (
--self-contained true) bundles the .NET runtime. The folder is 70 to 150 MB, but it runs on any Windows machine with nothing to install first. Choose this for software you distribute to the public. - Framework-dependent (
--self-contained false) is a few MB, but the user must have the matching .NET Desktop Runtime installed, or the app shows a download prompt on first launch. Fine for internal tools on managed machines.
Useful options:
-p:PublishReadyToRun=trueprecompiles the app for a faster start.-p:PublishSingleFile=truefolds the output into one.exe. It works, but an installer removes the reason to use it, and single-file apps unpack native libraries on first run. The plain folder is simpler.- Trimming (
PublishTrimmed) is not supported for WPF and WinForms; leave it off.
Set the app icon in the project file so the published .exe carries it:
<PropertyGroup>
<ApplicationIcon>app.ico</ApplicationIcon>
</PropertyGroup>
Run the published .exe once from the publish folder, ideally on a machine without Visual Studio, to make sure nothing is missing.
Step 2: zip the publish folder
Zip the contents of publish`: the .exe, the DLLs, .deps.json, .runtimeconfig.json and any content files. Leave out .pdb` files unless you want crash symbols on customers' machines.
Step 3: build the installer
- Upload the zip to ExeTup. It picks your app's
.exeas the main program; confirm it, since a self-contained publish includescreatedump.exe, which is not it. - Fill in the name, version (keep it in step with
<Version>in the project), publisher and licence. - Choose all users for a classic desktop app in Program Files, or current user when customers may lack admin rights.
- Keep 64-bit for a
win-x64publish; choose 32-bit forwin-x86. - Upload the same
app.ico, enable the shortcuts, and build.
Download Setup.exe and test the install and uninstall on Windows.
.NET-specific notes
- Updates. Ship a new installer with a higher version. Installing over the old version replaces the files; the installer does not include an auto-update channel.
- Settings and data. Write user data to
%APPDATA%or%LOCALAPPDATA%, not next to the.exe. Program Files is read-only for normal users, and the uninstaller only removes what it installed. - Prerequisites. Self-contained publishes need nothing else. If your app needs the Visual C++ runtime or a database driver, document it; the installer doesn't chain other installers.
- Code signing. Sign the published
.exebefore zipping, then sign the downloadedSetup.exe. See the SmartScreen guide.
Alternatives
- Visual Studio Installer Projects produce MSI files from inside Visual Studio. Still available as an extension, limited and awkward with self-contained publishes.
- ClickOnce gives per-user installs with auto-update, tied to a web server you maintain.
- WiX Toolset builds MSI files from XML and is the standard for enterprise-grade MSI packaging. Powerful, with a learning curve to match.
- MSIX is Microsoft's newer package format, best when you target the Microsoft Store.
See MSI vs EXE installers for when the format matters.
FAQ
Should I publish framework-dependent or self-contained?
Self-contained for anything you give to the public, so the app runs without a runtime download. Framework-dependent for internal tools on machines where IT manages the .NET runtime.
Does the installer include the .NET runtime?
If you publish self-contained, yes, because it is part of the publish folder. The installer ships whatever is in the zip.
Can I produce an MSI for Group Policy?
ExeTup builds a Setup.exe. It installs silently with /S, which covers most scripted deployment. For MSI-only policies, WiX is the right tool.
Which .NET versions does this work with?
Any that produce a publish folder: .NET 6, 7, 8, 9 and later, and .NET Framework apps built with Visual Studio (use the bin\Release output).
Related guides
- How to make a Setup.exe for your Windows app (no code)What a Setup.exe actually does, the three ways to make one, and how to turn an app folder into a professional installer in minutes without writing an installer script.
- MSI vs EXE installer: which one should your Windows app ship?The real differences between an MSI package and a Setup.exe, when IT departments actually need MSI, where MSIX fits, and why most desktop apps ship an EXE.
- "Windows protected your PC": what the SmartScreen warning means and how to get rid of itWhy Windows shows the "unknown publisher" warning on a new installer, what users can click, and how code signing and reputation make it go away.