What ClickOnce Is: How It Works, How Updates Work, and When It Fits or Does Not Fit in Practice
When people talk about distributing .NET desktop applications on Windows, ClickOnce quietly comes up again and again behind MSI and MSIX.
The easy mistake is to swing too far in one of these two directions:
- it is old technology, so we should not use it anymore
- it looks simple, so we can probably use ClickOnce for everything
Both are usually wrong.
ClickOnce is not a universal installer that can do everything.
At the same time, for internal .NET business applications where you want to distribute to standard users and keep updates running at low operational cost, it is still a very strong option.
This article explains what ClickOnce is, how it works, what it does well, and where it becomes the wrong tool, with a relatively large number of Mermaid diagrams to make the structure easier to follow. The discussion mainly assumes Microsoft Learn information that could be confirmed as of April 2026.
These diagrams are conceptual diagrams. In a Markdown environment that supports Mermaid, they render as diagrams.
Contents
- Table of Contents
- 1. The short answer
- See the positioning on one page first
- 2. What ClickOnce is
- Responsibilities that ClickOnce takes care of
- 3. What makes up ClickOnce
- How the four elements relate
- setup.exe is a helper, not the main actor
- 4. How installation and launch work
- From installation to the first launch
- Online-only versus available offline
- 5. How updates work
- Update detection starts from the deployment manifest
- Update flow
- Versions are kept separately
- 6. What ClickOnce does especially well
- 6.1 It is easy to distribute to standard users
- 6.2 You do not have to build your own updater
- 6.3 Applications are less likely to collide with each other
- 6.4 It is easy to publish from Visual Studio
- 6.5 Carrying settings forward is relatively straightforward
- 7. Where ClickOnce fits well
- A decision tree for whether it fits
- 8. Where ClickOnce does not fit well
- 8.1 You need machine-wide installation
- 8.2 Windows services, drivers, shell extensions, or heavy COM registration
- 8.3 You need package identity
- 8.4 You want to own update UX and distribution channels as part of the product
- 8.5 A simple copy-and-run tool is enough
- Which requirements push you toward another model
- 9. Common practical pitfalls
- 9.1 Do not view it with the same mental model as a traditional installer
- 9.2 Many old ClickOnce articles assume .NET Framework
- 9.3 Treat prerequisites separately
- 9.4 Carrying settings forward depends on what you save and how you save it
- 9.5 Do not take signing and update paths lightly
- 9.6 Review deploymentProvider if you move the publish location
- Operational flow from publish to update pickup
- 10. Summary
- 11. Related Articles
- Related Topics
- Windows Technical Topics
- Services Connected to This Topic
- Windows App Development
- Technical Consulting & Design Review
- Author Profile
- Go Komura
- 12. References
Table of Contents
- The short answer
- What ClickOnce is
- What makes up ClickOnce
- How installation and launch work
- How updates work
- What ClickOnce does especially well
- Where ClickOnce fits well
- Where ClickOnce does not fit well
- Common practical pitfalls
- Summary
- Related Articles
- References
1. The short answer
In one sentence, ClickOnce is a deployment technology for .NET Windows desktop applications that makes it easy to distribute per-user and keep updates running automatically.
It tends to fit well in cases like these:
- internal WinForms or WPF business applications
- installation should work for standard users
- per-user distribution is enough
- built-in update behavior is enough
- a website or file share is sufficient as the delivery path
And it is usually safer to start with another model if you need:
- machine-wide installation for all users
- Windows services, drivers, in-process shell extensions, or heavy COM registration
- package identity
- rollout channels, staged rollout, or custom rollback UX
- an installer with larger responsibilities for integrating deeply into the OS
So the practical summary is simple: ClickOnce is strong for easy distribution and easy updates, but not a good fit for applications with heavy OS integration requirements.
See the positioning on one page first
flowchart TD
A["Need to distribute a Windows app"]
B{"Are there requirements for deep OS integration?"}
C["Start by comparing MSI / MSIX"]
D{"Is it a .NET Windows desktop app<br/>and is per-user deployment enough?"}
E{"Do you want to distribute to standard users?"}
F{"Is built-in updating enough?"}
G["ClickOnce is a strong candidate"]
H["Also compare xcopy / a custom updater"]
A --> B
B -- Yes --> C
B -- No --> D
D -- No --> H
D -- Yes --> E
E -- No --> H
E -- Yes --> F
F -- Yes --> G
F -- No --> H
2. What ClickOnce is
ClickOnce is a Microsoft technology for deploying Windows applications.
Officially, it is described as a deployment technology for Windows-based applications that can be installed and run with minimal user interaction and can update themselves.
The important part is not to think of ClickOnce as just “one kind of installer.”
In practice, ClickOnce is a deployment model that takes care of all of these together:
- which version should be distributed
- which files belong to that version
- how updates are detected
- where updates are downloaded from
- how the application is kept in a safe location per user
- how integrity is checked at launch time
So the real center of ClickOnce is not setup.exe itself.
It is closer to a manifest-centered system that handles distribution, updates, and cache management together.
ClickOnce is also still a normal option in current .NET. In Visual Studio, the Publish tool flow is used for .NET Core 3.1 and .NET 5 or later, and if you need to work with manifests manually, the tool is dotnet-mage.exe.
Responsibilities that ClickOnce takes care of
flowchart LR
CO["ClickOnce"]
V["Which version should be delivered"]
U["Where updates are downloaded from"]
S["Store safely in a per-user location"]
I["Verify integrity and launch"]
CO --> V
CO --> U
CO --> S
CO --> I
3. What makes up ClickOnce
When you want to understand how ClickOnce works, it helps a lot to look at these four pieces:
| Element | Role |
|---|---|
Deployment manifest (.application) |
Represents the version that should currently be delivered, along with update location and update behavior |
Application manifest (*.exe.manifest) |
Represents the contents of that version, including dependencies, hashes, and the entry point |
| Application files | The exe, dll, config files, data files, and so on |
setup.exe (optional) |
A bootstrapper that checks and installs prerequisites when required runtimes or dependencies must be prepared first |
The core here is the two kinds of manifest.
- the deployment manifest says which version is currently the correct one
- the application manifest says what is inside that version
So update detection starts from the deployment manifest, while the application manifest determines what actually needs to be downloaded.
How the four elements relate
flowchart LR
Setup["setup.exe<br/>optional<br/>checks / installs prerequisites"]
Deploy["Deployment manifest (.application)<br/>which version should be delivered<br/>update source / update conditions"]
App["Application manifest (*.exe.manifest)<br/>what is inside that version<br/>file list / hashes / entry point"]
Files["Application files<br/>exe / dll / config / data"]
Cache["ClickOnce cache<br/>per-user / per-application"]
Setup --> Deploy
Deploy --> App
App --> Files
Files --> Cache
setup.exe is a helper, not the main actor
setup.exe is often the visible part, but it is not the main point of ClickOnce.
Its role is to check and install prerequisites.
For example, if the app needs the correct .NET runtime or extra redistributable components, setup.exe can prepare those first and then hand off to the ClickOnce deployment itself.
4. How installation and launch work
If we simplify the ClickOnce flow for practical work, it looks like this:
- The user opens
setup.exeor.applicationfrom a web page or a file share - If the deployment uses
setup.exe, prerequisites are checked and missing ones are installed - ClickOnce reads the deployment manifest
- It reads the application manifest referenced by the deployment manifest
- Required files are obtained and placed into the per-user ClickOnce cache
- If the configuration allows offline use, the app is registered in the Start menu or app list
- After that, the app is launched under ClickOnce management
The key point is that this is not the same idea as putting files under Program Files like a traditional installer.
ClickOnce applications go into a safe cache location per user, and they are separated by application and by user. That separation is one of the major characteristics of ClickOnce.
From installation to the first launch
sequenceDiagram
participant U as User
participant P as setup.exe / .application
participant D as Deployment manifest
participant A as Application manifest
participant C as ClickOnce cache
participant X as Application
U->>P: Open
Note over U,P: In a setup.exe-based configuration,<br/>prerequisite checks happen first
P->>D: Retrieve and read
D->>A: Refer to the target version
A->>C: Obtain required files and verify integrity
C->>X: Place and launch
Online-only versus available offline
ClickOnce broadly has two ways of presenting the app:
- online-only: it runs starting from the published location, with less of a permanently installed feel
- available offline: it is installed onto the user’s machine and can also be launched from the Start menu
For internal business applications, the practical choice is often available offline.
flowchart LR
subgraph Online[Online-only]
O1["Start from the published location"]
O2["Less of a permanently installed feel"]
O3["More likely to assume network availability"]
O1 --> O2 --> O3
end
subgraph Offline[Available offline]
F1["Install into the user's area"]
F2["Register in the Start menu"]
F3["Launch locally"]
F4["Check for updates at defined timing"]
F1 --> F2 --> F3 --> F4
end
5. How updates work
The clearest strength of ClickOnce is probably that its update model is built in.
Update detection starts from the deployment manifest
ClickOnce applications read the deployment manifest to check:
- whether a newer version exists
- whether the update is mandatory
- where the update should be downloaded from
Once an update starts, ClickOnce uses file patching to avoid unnecessary full re-downloads. In practical terms, it is fine to think of it as comparing the new application manifest with the current one and then downloading only the files that changed.
The common patterns for update timing are these:
- check before startup
- check after startup
- provide a “check for updates” UI in the application
That said, .NET Framework and .NET 5+ differ in available APIs and configuration surfaces. The important point is not to start implementation from old ClickOnce memory alone.
Update flow
flowchart TD
Start["Application starts"]
Check["Check the deployment manifest"]
New{"Is there a newer version?"}
Run["Launch as-is"]
Get["Get the new application manifest"]
Compare["Compare signatures / hashes"]
Download["Download only the changed parts"]
Switch["Establish the new version and switch over"]
Restart["If needed, run the new version after restart"]
Start --> Check --> New
New -- No --> Run
New -- Yes --> Get --> Compare --> Download --> Switch --> Restart
It is also useful in practice to remember that if the network is unavailable, the app may simply continue without performing an update check.
Versions are kept separately
ClickOnce is closer to “establish the new version correctly and then switch over” than to “overwrite the current files in place.”
In addition, the ClickOnce cache keeps the current version and the previous version separately. That is one reason it is easier to avoid polluting the environment or causing version collisions.
flowchart TB
subgraph UA[ClickOnce cache for User A]
APrev["Previous version"]
ACur["Current version"]
AData["Settings / data"]
end
subgraph UB[ClickOnce cache for User B]
BPrev["Previous version"]
BCur["Current version"]
BData["Settings / data"]
end
APrev --> ACur
AData --> ACur
BPrev --> BCur
BData --> BCur
The two practical points here are:
- it is less likely to mix between different users
- it is less likely to collide between different versions
That reduced risk of DLL Hell comes from this structure more than people often realize.
6. What ClickOnce does especially well
The value of ClickOnce is not only that it is easy to distribute. In practice, these are the points that matter most.
6.1 It is easy to distribute to standard users
ClickOnce fits naturally with per-user deployment, and one of its biggest strengths is that it is comparatively easy to install without administrator rights.
This is a very common real-world situation in internal business applications:
- the users are standard users
- you do not want to open an installation request with IT every single time
- but you also do not want updates to stall
Under those conditions, ClickOnce is very strong.
Its basic premise already matches the need to install safely into each user’s area with updates included.
6.2 You do not have to build your own updater
If you build automatic updates from scratch, the amount of work grows faster than it first appears:
- checking for a new version
- downloading it
- validating integrity
- switching from the old version
- recovering from failures
- building update UI
- handling the updater itself
ClickOnce already covers a large portion of that with an existing model.
flowchart LR
subgraph Custom[Responsibilities owned by a custom updater]
C1["Detect a new version"]
C2["Download"]
C3["Verify integrity"]
C4["Switch over"]
C5["Recover from failures"]
C1 --> C2 --> C3 --> C4 --> C5
end
subgraph Click[Responsibilities that can be pushed to ClickOnce]
K1["Detect a new version"]
K2["Obtain and verify"]
K3["Switch over"]
K1 --> K2 --> K3
end
That does not mean it lets you do everything freely.
But it covers a lot of the “good enough update behavior” that internal business apps need.
6.3 Applications are less likely to collide with each other
ClickOnce applications are separated by application, by user, and by version.
That makes it less likely to run into old-style problems such as:
- version conflicts in shared components
- overwriting a DLL and breaking another application
- polluting the environment through manual replacement
6.4 It is easy to publish from Visual Studio
ClickOnce works well with Visual Studio publishing, which also means the distance from build to delivery is short.
Before stepping into a different kind of complexity such as MSI authoring, it is easier to:
- publish something first
- distribute it first
- get updates flowing first
- get feedback from the field first
6.5 Carrying settings forward is relatively straightforward
When you use the default application settings provider, ClickOnce has a mechanism to merge settings from the previous version into the new one during updates.
But that works on the assumption that you are using the default settings provider. Once you move into custom settings storage, custom providers, or changed save locations, it naturally becomes a different story.
7. Where ClickOnce fits well
ClickOnce is particularly well suited to cases like these:
| Situation | Why ClickOnce fits well |
|---|---|
| Internal WinForms or WPF business apps | Standard-user distribution and automatic updates line up naturally |
| Per-user installation is enough | Per-user deployment is the natural model |
| You want to distribute through a website or UNC share | The delivery path stays simple |
| Updates happen about weekly or monthly | Built-in updates are usually enough |
| You do not want update UI itself to become part of the product value | You can use the existing update model |
Concrete examples that often match well are:
- internal data-entry applications
- desktop business tools for estimates, ordering, receiving, or inventory
- helper applications for equipment configuration
- internal clients distributed to branches, factories, or back-office users
- apps that should update, but do not justify building a dedicated updater
In these kinds of applications, keeping deployment and updates simple is itself part of the value. ClickOnce answers that need fairly directly.
A decision tree for whether it fits
flowchart TD
S["Organize the requirements"]
Q1{"Is it a .NET desktop app<br/>such as WinForms or WPF?"}
Q2{"Is per-user deployment enough?"}
Q3{"Do you want standard-user installation?"}
Q4{"Can it be distributed through the web or a file share?"}
Q5{"Is it acceptable not to overbuild update UX?"}
G["ClickOnce is a very strong candidate"]
O["Compare other approaches"]
S --> Q1
Q1 -- No --> O
Q1 -- Yes --> Q2
Q2 -- No --> O
Q2 -- Yes --> Q3
Q3 -- No --> O
Q3 -- Yes --> Q4
Q4 -- No --> O
Q4 -- Yes --> Q5
Q5 -- Yes --> G
Q5 -- No --> O
8. Where ClickOnce does not fit well
There are also clear situations where forcing ClickOnce is usually the wrong move.
8.1 You need machine-wide installation
ClickOnce is fundamentally a per-user model.
- you want one installation shared by all users
- you want installation under
Program Files - you want to deploy and manage it at the whole-machine level
If that is the requirement, MSI or another installer model is usually more natural than ClickOnce.
8.2 Windows services, drivers, shell extensions, or heavy COM registration
This is the category where the application touches the OS deeply.
- Windows services
- drivers
- in-process shell extensions
- designs that depend on mechanical COM registration
Once those enter the picture, you are outside the “lightweight distribution” worldview of ClickOnce.
8.3 You need package identity
One reason to choose MSIX is when package identity itself is part of the requirement.
ClickOnce is not aimed in that direction. If what you want is modern packaging or features that depend on Windows package identity, MSIX is the more natural starting point.
8.4 You want to own update UX and distribution channels as part of the product
For example, if you want things like:
- stable, beta, and preview channels
- staged rollout
- rollout control based on telemetry
- fine-grained control over background download
- custom rollback strategies
- a more complex lifecycle for the updater itself
then ClickOnce’s built-in update model starts to fall short.
8.5 A simple copy-and-run tool is enough
There are also cases where a simpler option is better:
- the app works if you just place the folder
- manual replacement is enough for updates
- distribution happens by USB
- simplicity matters more than anything else in a closed environment
In cases like that, xcopy deployment can create less friction.
Which requirements push you toward another model
flowchart LR
A1["Install for all users"] --> B1["MSI / in some cases MSIX"]
A2["Service / driver / shell extension / heavy COM"] --> B2["MSI / dedicated installer"]
A3["Need package identity"] --> B3["MSIX"]
A4["Staged rollout / channels / custom UX"] --> B4["Custom updater"]
A5["Simple copy is enough"] --> B5["xcopy"]
So ClickOnce is not universal in either direction.
It is strongest in projects with the right amount of complexity.
9. Common practical pitfalls
ClickOnce is convenient, but it is easy to stumble if you go in too casually. These are especially worth understanding in advance.
9.1 Do not view it with the same mental model as a traditional installer
ClickOnce is not a model where people directly manage a fixed installation location in an easy-to-browse way.
The actual files live in the ClickOnce-managed cache and are separated by version.
Because of that, it does not fit well with practices such as:
- operations that assume a fixed EXE path
- manually overwriting files in place
- operations where humans are expected to directly control the physical file location
ClickOnce is not a file-placement model managed by people; it is a deployment-state model managed by manifests.
9.2 Many old ClickOnce articles assume .NET Framework
This matters a lot.
Even now, many high-ranking search results for ClickOnce are based on the .NET Framework era.
Modern .NET is a little different.
- on .NET Core 3.1, .NET 5, and .NET 6, the
ApplicationDeploymentAPI cannot be used in the old way - from .NET 7 onward, some deployment properties can be read through environment variables
- if you work with manifests manually,
dotnet-mage.exebecomes the relevant tool - Visual Studio publishing also no longer maps one-to-one to older Publish Wizard assumptions
So even if you think “I already know ClickOnce,” it is safer not to implement it from old memory alone.
9.3 Treat prerequisites separately
ClickOnce is a deployment model, but the application may still depend on prerequisites:
- the required runtime
- additional redistributable components
- other dependencies
That is where a bootstrapper configuration using setup.exe helps. If this part stays vague, you end up with “it was distributed by ClickOnce, but it still does not run.”
9.4 Carrying settings forward depends on what you save and how you save it
If you stay with the default settings provider, migration of settings during updates is relatively straightforward.
But naturally, it becomes different if you have:
- a custom settings provider
- roaming-oriented behavior
- your own custom save location
- large structural changes in settings between versions
9.5 Do not take signing and update paths lightly
ClickOnce gives you a deployment and update mechanism, but that does not make the security responsibility disappear.
Especially in production, it is worth sorting out early:
- how signing certificates are managed
- how the publisher name is presented
- how the update source is controlled
- how test-time self-signed certificates are separated from production signing
flowchart TD
Cert["Code-signing certificate"]
AppMan["Application manifest"]
DepMan["Deployment manifest"]
Verify["Client-side verification"]
Run["Update / run"]
Tamper["Manifest tampering"]
Stop["Stop on verification failure"]
Cert --> AppMan
Cert --> DepMan
AppMan --> Verify
DepMan --> Verify
Verify --> Run
Tamper -. Verification failure .-> Stop
“Automatic updates exist, so we are safe” is the wrong conclusion. You still need to think separately about what is being trusted and how that trust is maintained.
9.6 Review deploymentProvider if you move the publish location
This is subtle, but it causes a lot of trouble in real work.
An installed ClickOnce app looks to the location referenced by deploymentProvider in the deployment manifest as its update source.
That means even if you copy the whole published folder to another URL or another share, clients may continue to look at the old location unless deploymentProvider is updated.
And once you edit the manifest by hand, you need to sign it again.
Operational flow from publish to update pickup
flowchart TD
Build["Build"]
AppManifest["Generate the new application manifest"]
SignApp["Sign the application manifest"]
UpdateDep["Update the deployment manifest to the new version"]
SignDep["Sign the deployment manifest"]
Publish["Place it in the publish location"]
Client["Client detects the update"]
Build --> AppManifest --> SignApp --> UpdateDep --> SignDep --> Publish --> Client
So the practical point is that what matters in ClickOnce operations is not only whether the files were placed somewhere, but whether the manifests and signatures remain consistent with each other.
10. Summary
In one sentence, ClickOnce is:
a way to distribute .NET Windows desktop applications
per-user, simply, and with updates at relatively low operational cost
Its main strengths are:
- it is easy to distribute to standard users
- it has a built-in update model
- it can update only the changed parts efficiently
- it separates applications and versions cleanly
- it is easy to publish from Visual Studio
- it matches internal business applications well
But it is not universal.
- machine-wide installation
- services, drivers, and shell extensions
- heavy COM registration
- package identity
- custom channels or staged rollout
- update UX treated as part of the product value
If those are real requirements, you should start from MSI, MSIX, or a custom updater instead of forcing ClickOnce.
So ClickOnce is not a simple installer that can take anything.
What it is, instead, is still a very strong option where the project fits it well.
If what you want to distribute is:
- a .NET Windows business application
- where per-user installation is sufficient
- where you want to distribute to standard users
- and where you do not want to own update implementation yourself
then ClickOnce belongs on the shortlist.
11. Related Articles
- How to Choose a Windows App Deployment Model - MSI, MSIX, ClickOnce, xcopy, and Custom Updaters
- When Does a Windows App Really Need Administrator Privileges?
Related Topics
This is the topic page most closely connected to this article. From there, you can continue to related services and other articles.
Windows Technical Topics
This is the entry page that organizes technical topics around Windows development, bug investigation, and working with existing assets.
Services Connected to This Topic
This article naturally connects to the following service pages. Please start from whichever is closest to your situation.
Windows App Development
For internal business apps, device-configuration tools, and improvements to existing software, the least-friction choice among ClickOnce, MSI, MSIX, and xcopy often depends heavily on requirement review before implementation starts.
Technical Consulting & Design Review
Questions such as whether ClickOnce is enough, whether the design should move toward MSIX or MSI, and whether automatic updating should stay built-in or be owned by the team become much easier to answer when they are organized before implementation begins.
Author Profile
Go Komura
Representative of KomuraSoft LLC
My main focus is Windows software development, technical consulting, and bug investigation, especially for projects that still carry existing assets or problems whose root causes are difficult to see at first.
12. References
- Microsoft Learn - ClickOnce deployment and security
- Microsoft Learn - ClickOnce for .NET on Windows
- Microsoft Learn - How ClickOnce performs application updates
- Microsoft Learn - Choosing a ClickOnce update strategy
- Microsoft Learn - ClickOnce deployment manifest
- Microsoft Learn - ClickOnce application manifest
- Microsoft Learn - ClickOnce cache overview
- Microsoft Learn - ClickOnce and application settings
- Microsoft Learn - Install prerequisites with a ClickOnce application
- Microsoft Learn - ClickOnce and Authenticode
- Microsoft Learn - Security, versioning, and manifest issues in ClickOnce deployments
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
When Windows Admin Privileges Are Actually Required: UAC, Protected Areas, and Practical Design Boundaries
A practical guide to when Windows admin privileges are truly required, covering UAC, protected locations, services, drivers, and per-user...
How to Choose a Windows App Deployment Model - MSI, MSIX, ClickOnce, xcopy, and Custom Updaters
A practical guide to choosing between MSI, MSIX, ClickOnce, xcopy deployment, and custom updaters for Windows applications.
How Far Can a Windows App Really Be a Single Binary? What Fits in One EXE and What Still Depends on Windows
A practical guide to what can really be bundled into one Windows executable, where OS dependencies remain, and how to decide before shipp...
How to Use Windows Sandbox to Speed Up Windows App Validation - Admin Rights, Clean Environments, and Reproducing Missing-Permission or Low-Resource Cases
A practical guide to using Windows Sandbox to validate Windows apps faster by separating admin-rights issues, reproducing clean-environme...
Where Unit Tests End and Integration Tests Begin - A Practical Boundary Guide
A practical guide to drawing the boundary between unit tests and integration tests by separating pure logic, formatting, wiring, environm...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.
Technical Consulting & Design Review
We help clarify design direction, architectural boundaries, lifetime ownership, and how to handle legacy Windows assets.