How to Publish and Deploy a .NET WPF Utility
Building a small desktop utility is only half the job. Getting it onto your machine, placing it where you can launch it quickly, and keeping the deployment lightweight enough that you never think about it again is the other half. Too many developers over-engineer this step, introducing installer frameworks or cross-platform tooling for an application that only ever runs on one workstation.
In his video "How to Publish and Deploy a .NET WPF Utility", Tim Corey walks through how he publishes his personal image viewer app to a single executable, copies it to a folder, and wires it into the Windows right-click context menu using the registry. We'll cover each decision he makes along the way, from framework-dependent versus self-contained builds to the registry entries that make the utility accessible from any folder. If you have built a small tool for yourself and want the simplest possible deployment story, this article lays out the approach.
Publishing from Visual Studio
[1:03 - 1:25] Tim starts by right-clicking the project in Visual Studio and selecting Publish. The wizard presents several targets (Azure, Docker, ClickOnce), but he bypasses all of them and chooses Folder. For a personal utility that lives on your own machines, a folder publish is the most direct path: it produces files you can copy wherever you need them without any deployment infrastructure.
After selecting the folder target, Tim skips directly to the settings page rather than running the publish immediately. The defaults need adjusting before the output will match what he wants.
Framework-Dependent vs. Self-Contained
[1:25 - 2:32] The first setting is deployment mode. A framework-dependent build assumes the .NET SDK or runtime is already installed on the target machine. The output is small, roughly 200 kilobytes for this application, because it relies on the shared runtime that exists on your system.
A self-contained build bundles the entire .NET runtime into the output. That makes the package portable to machines without .NET installed, but inflates the size to around 140 megabytes. Tim chooses framework-dependent because every machine he uses already has .NET installed. If you are distributing a tool to colleagues or customers who might not have the runtime, self-contained is the safer bet, but for personal utilities the tradeoff rarely makes sense.
Why WPF and Not MAUI
[2:50 - 4:10] Tim addresses feedback he received about using WPF instead of MAUI for this project. His reasoning is practical rather than ideological. The image viewer only needs to run on Windows. Introducing MAUI and its cross-platform layer adds overhead without delivering any benefit for a single-platform tool.
Beyond the architectural argument, there is a maintenance angle. Tim's original source code has survived roughly seven years across four or five machines with minimal changes. The only updates were framework upgrades (from .NET Framework to .NET 8, and now to .NET 10). If the utility had been built on a framework that requires attention every time Apple or Google ships an OS update, those seven years of hands-off operation would not have been possible. A utility that costs more time to maintain than it saves is no longer saving you anything.
Single File Publish and PDB Files
[4:59 - 6:32] With the deployment mode settled, Tim enables "Produce single file" and targets Windows x64. The publish completes and opens the output folder, which contains two files: the .exe and a .pdb.
That second file is a Program Database file, and its role is worth understanding. When you compile in Release mode, the compiler optimizes and renames internal symbols for performance. The PDB maps those optimized names back to your actual codebase, allowing you to attach a debugger to the running executable and set breakpoints as though you were working in Debug mode. For a production application serving customers, you should store PDB files securely alongside each release so you can diagnose issues after deployment.
For a tool you built for yourself, Tim notes that the PDB is not required for the application to run. He deletes it for simplicity, but cautions viewers not to adopt that habit for anything shipped to users. The single .exe runs on its own without the PDB present.
One quirk worth noting: if you switch from framework-dependent to self-contained and keep "single file" enabled, the output is no longer a single file. Additional runtime files appear alongside the executable. The single-file option only produces a true single file when paired with a framework-dependent build.
Placing the Utility on Your Machine
[7:17 - 7:52] With the executable in hand, Tim moves it to a permanent location. He uses a dedicated C:\Apps\SimpleImageViewer folder, a convention that keeps personal tools separate from Program Files and easy to locate. The executable from 2024 still runs identically on his current machine, which reinforces the earlier point about longevity: a well-scoped utility with a simple project structure can survive hardware changes and OS upgrades without modification.
Adding the Tool to the Right-Click Menu
[7:52 - 10:21] The final step wires the utility into Windows Explorer's context menu. Tim modifies the Windows Registry to add entries under two locations: one for right-clicking on a folder (so you can open a directory of images) and one for right-clicking on whitespace within a folder (to launch the viewer in the current directory).
Each registry entry creates a shell command that passes the selected path as a command-line argument to the executable. This is where the args parameter in the application's entry point receives its value.
Tim provides a .reg file but renames it to .txt before sharing. That precaution matters: double-clicking a .reg file immediately prompts to write values into the registry, and running an untrusted registry file can cause serious system problems. His approach requires you to open the file, verify the paths, update them to match your machine, rename the extension back to .reg, and only then execute it. If any of that sounds unfamiliar, Tim's advice is direct: do not modify the registry.
For developers comfortable with the registry, the two entries are straightforward. Each one creates a named shell command under the appropriate key, pointing to your executable's full path with a %V or %1 placeholder that passes the target directory or file path at runtime. A reboot may be needed before the new context menu entries appear.
Wrapping Up: Deploy Once, Use Forever
[10:21 - 10:30] The entire deployment process is two steps: publish to a folder, then register the executable in the right-click menu. No installer, no update mechanism, no cloud service. For a single-purpose utility on your own machine, that simplicity is the point.
Conclusion
[10:30 - 10:40] To sum it up: dotnet publish with framework-dependent and single-file settings produces a lightweight executable you can drop anywhere. A pair of registry entries turns it into a context menu action available anywhere in Windows Explorer.
The lesson that runs through the whole video is restraint. Match your deployment approach to the scope of your application. A utility built for personal use does not need the same infrastructure as a product shipped to thousands of customers, and treating it that way only creates maintenance work that erodes the time the tool was built to save.
Example Tip: Keep your PDB files even for personal projects. Store them in the same folder as the executable or a nearby archive. If the utility ever behaves unexpectedly months later, having the PDB lets you attach Visual Studio and debug the release build without recompiling from source.
Watch full video on his YouTube Channel and gain more insights on deploying .NET desktop applications.

