What ClickOnce Actually Is: How It Works, How Updates Flow, and Where It Fits in Practice

· · Windows, Deployment, ClickOnce, .NET, Windows Development

ClickOnce is Microsoft’s deployment technology for .NET Windows desktop apps (WinForms / WPF) that lets you ship to standard users with no admin rights and keep automatic updates running on top.

It’s not a universal installer. It’s a great fit for the narrower problem of “internal line-of-business apps I want to push out lightly and keep updated automatically.”

1. Short version

ClickOnce fits when:

  • it’s a WinForms / WPF internal business app
  • you want to install as a standard user (no admin rights)
  • per-user deployment is enough
  • you want auto-update built in
  • you can host it on a web server or file share

ClickOnce does not fit when:

  • you need a machine-wide install for all users
  • you’re shipping a Windows service, driver, or shell extension
  • you need complex COM registration
  • you need package identity (MSIX is the right answer)
  • you need staged rollouts or a custom update UI

2. The four moving parts of ClickOnce

Part Role
Deployment manifest (.application) declares “which version is current right now,” plus the update location and policy
Application manifest (.exe.manifest) declares “what’s inside this version” — file list, hashes, entry point
The app itself exe, dlls, config, data files
setup.exe (optional) checks and installs prerequisites (.NET runtime, etc.). Supporting actor, not the star

Key point: the manifests are ClickOnce. setup.exe is just a helper.

3. How updates work

A ClickOnce update flows like this:

  1. on launch, the app checks the deployment manifest
  2. if a newer version exists, fetch the new application manifest
  3. compare file hashes and download only the files that actually changed
  4. stage the new version in the cache, then switch over

What’s worth knowing:

  • it’s not an in-place overwrite — the new version is fully staged before the swap
  • the current and previous versions sit side by side in the cache (much harder to hit DLL Hell)
  • isolation is per-app, per-user, and per-version
  • if there’s no network, the app skips the update check and just runs

Three update timing options

  1. check before launch (default)
  2. check after launch
  3. expose an “Update now” button inside the app and trigger it yourself

4. What ClickOnce does well

4.1 Easy to ship to standard users

No admin rights needed. IT doesn’t have to be in the loop for every install on a standard-user machine.

4.2 You don’t have to build your own updater

Update detection, download, integrity check, switch-over, and rollback on failure are all built in.

4.3 Apps don’t collide with each other

Apps and versions are isolated, so you don’t get DLLs overwriting each other.

4.4 One-click publish from Visual Studio

The Publish wizard gets you into a real distribute-and-update loop very quickly.

4.5 Settings carry over

If you use the default settings provider, user settings from the previous version migrate forward automatically on update.

5. Where it fits and where it doesn’t

Good fit

| Situation | Why | |——|——| | internal LOB apps (data entry, quoting, inventory, etc.) | distribution and updates stay simple | | per-user install is fine | per-user is ClickOnce’s native model | | can be served from web or a file share | distribution path is straightforward | | weekly to monthly update cadence | the built-in updater handles this comfortably |

Poor fit

| Requirement | Better choice | |——|——–| | machine-wide install | MSI | | service / driver / shell extension | MSI or a dedicated installer | | package identity required | MSIX | | staged rollout / custom update UX | a custom updater | | simple drop-in tool with no install needed | xcopy |

6. Pitfalls you’ll actually hit

6.1 Doesn’t play well with fixed-path workflows

ClickOnce apps live in a managed cache directory, so workflows that assume “the EXE is always at this path” don’t work.

6.2 Watch out for old ClickOnce articles

Most of the writing online is from the .NET Framework era. On modern .NET (.NET Core / 5+), some things have changed:

  • the ApplicationDeployment API is not available on .NET Core 3.1 / .NET 5 / 6
  • if you’re working with manifests by hand, use dotnet-mage.exe
  • the Visual Studio publish flow itself has changed

6.3 Prerequisites are a separate problem

Things like the .NET runtime or VC++ redistributables still need to be installed separately via setup.exe (the bootstrapper).

6.4 Signing and distribution paths need care

  • you need a real code-signing certificate for production
  • if the distribution URL changes, update deploymentProvider in the deployment manifest
  • any time you edit a manifest, re-sign it

6.5 Online-only vs. offline-capable

  • online-only: launches from a published URL. Doesn’t really feel installed
  • offline-capable: gets a Start menu entry and can launch locally. This is what you usually want for internal business use

7. Wrap-up

ClickOnce is the deployment model that shines on the projects with just-the-right amount of complexity.

  • a .NET Windows business app you want to ship per-user without friction
  • updates you want to keep running cheaply
  • a standard-user audience

If those line up, ClickOnce is still a strong choice today. On the other hand, anything that needs deep OS integration or sophisticated rollout control belongs on MSI or MSIX instead.

Further reading

Related Articles

Recent articles sharing the same tags. Deepen your understanding with closely related topics.

Related Topics

These topic pages place the article in a broader service and decision context.

Where This Topic Connects

This article connects naturally to the following service pages.

Back to the Blog