What Is ClickOnce? - How It Works, How It Updates, and Where It Fits (and Doesn't) in Practice
· Updated: · Go Komura · Windows, Deployment, ClickOnce, .NET, Windows Development
Revision history (1 updates, last updated Sep 1, 2026)
A log of the changes made to this article. Where a pre-update version was archived, it stays readable at a permanent DOI link.
- Retranslated as a full translation of the Japanese original. The previous English version was an abridgement that carried only part of the source, so sections, tables, Mermaid diagrams, figure captions and FAQ entries were missing. All of them have been restored to match the Japanese original, and the technical claims are the same as in the Japanese version. Read the version before this update (DOI: 10.5281/zenodo.21614613)
- First published
Cite this article(DOI: 10.5281/zenodo.21614612)
This article is archived on Zenodo. Below are both the DOI that always resolves to the latest version and the DOI pinned to the version you are reading.
Go Komura (2026). What Is ClickOnce? - How It Works, How It Updates, and Where It Fits (and Doesn't) in Practice. KomuraSoft LLC. https://doi.org/10.5281/zenodo.21614612 https://comcomponent.com/en/blog/2026/04/13/001-clickonce-what-is/
- DOI (latest version)
- 10.5281/zenodo.21614612
- DOI (this version)
- 10.5281/zenodo.22220437
When the conversation turns to distributing .NET desktop apps on Windows, one name keeps quietly coming up in the shadow of MSI and MSIX: ClickOnce.
But if you swing carelessly to either of these positions:
- It’s old technology, so we don’t use it anymore
- Or conversely, it looks easy, so ClickOnce can handle anything
you will usually be wrong.
ClickOnce is not an all-purpose installer that can do everything. On the other hand, for distributing internal .NET line-of-business apps to standard users, with updates included, at low operational cost, it remains a very strong option even today.
This article organizes what ClickOnce is, how it works, what it does well, and where it starts to strain — from a practical standpoint, with plenty of Mermaid diagrams. The content is primarily based on Microsoft Learn information verifiable as of April 2026.
The diagrams are conceptual. In Markdown environments with Mermaid support, they render as figures.
Who This Article Is For
This is written for developers deciding how to distribute a .NET Windows desktop app (WinForms / WPF) and for the IT staff who will run that distribution and its updates. It assumes you have not yet decided whether to use ClickOnce, so the material for that decision comes first and the actual publishing steps are in 6.4.
Terms Worth Knowing Up Front
A handful of terms appear repeatedly below. Here is what they mean, so the first occurrence does not trip you up.
| Term | Meaning |
|---|---|
| per-user | Installed separately for each user. It goes under that user’s profile and is invisible to other users on the same machine. In most cases it can be installed without administrator rights |
| machine-wide | Installed once per machine, with every user sharing the same copy. Because it lands in a shared location such as Program Files, installing it normally requires administrator rights |
| bootstrapper | A small installer program that runs before the app itself, checking for and installing prerequisites such as required runtimes and redistributable packages. In ClickOnce, setup.exe plays this role |
| file patching | On update, fetching only the files that changed relative to the previous version, instead of re-downloading every file in the new version |
| deploymentProvider | The entry written into the deployment manifest that says where to go for updates. It is a URL or a UNC path, and installed clients keep looking at it |
| package identity | The unique identifier Windows recognizes for a package such as an MSIX. It is made up of five parts — name, version, architecture, ResourceId, and publisher — and some Windows features depend on it. Apps distributed with ClickOnce do not have one |
| DLL Hell | The classic Windows problem where another app overwrites a shared DLL or swaps it for a different version, breaking applications that used to work |
Table of Contents
- The Conclusion First
- What Is ClickOnce?
- What Makes Up ClickOnce
- The Flow from Install to Launch
- How Updates Work
- Where ClickOnce Excels
- Where It Fits
- Where It Doesn’t Fit
- Common Pitfalls in Practice
- Summary
- Related Articles
- References
Knowledge map for this article
ClickOnce is a deployment model for .NET Windows desktop applications that handles distribution, updating, and cache management together, centered on the deployment manifest and the application manifest. It reaches standard users without administrator privileges through per-user deployment, fetches only what has changed through file patching, and makes DLL Hell easier to avoid through a ClickOnce cache that is isolated per application, per user, and per version. On the other hand, it does not suit requirements that call for a machine-wide install, OS integration such as a Windows service or a driver, or package identity, and those should be considered starting from MSI or MSIX. A code signing certificate is used to sign the manifests, and moving the deployment location makes revisiting deploymentProvider and re-signing indispensable.
flowchart LR
accTitle: ClickOnce
accDescr: Diagram showing how ClickOnce delivers per-user deployment and automatic updates through file patching around the deployment manifest and the application manifest, while requirements that need a machine-wide install, package identity, or a Windows service should lean toward MSI or MSIX
clickonce["ClickOnce"]
per_user_deployment["Per-User Deployment"]
deployment_manifest["Deployment Manifest (.application)"]
application_manifest["Application Manifest (*.exe.manifest)"]
code_signing_cert["Code signing certificate"]
clickonce_cache["ClickOnce Cache"]
dll_hell["DLL Hell"]
setup_exe_bootstrapper["setup.exe (ClickOnce Bootstrapper)"]
file_patching["Differential File Patching"]
deployment_provider["deploymentProvider"]
machine_wide_install["Machine-Wide Install"]
msi["MSI (Windows Installer)"]
admin_rights["Administrator Privileges"]
msix["MSIX"]
package_identity["Package Identity"]
windows_service["Windows Service"]
publish_tool["Publish Tool (Visual Studio)"]
dotnet[".NET (Core and Later)"]
dotnet_mage["dotnet-mage.exe"]
application_deployment_api["ApplicationDeployment API"]
dotnet_framework[".NET Framework"]
pubxml["Publish Profile (.pubxml)"]
offline_availability["Available Offline Mode (ClickOnce)"]
application_settings_migration["ClickOnce Application Settings Migration"]
self_signed_cert["Ad Hoc Self-Signed Certificate"]
clickonce -->|"uses"| deployment_manifest
deployment_manifest -->|"uses"| application_manifest
application_manifest -.->|"configured by"| code_signing_cert
deployment_manifest -.->|"configured by"| code_signing_cert
clickonce -->|"uses"| clickonce_cache
clickonce_cache -->|"mitigates"| dll_hell
setup_exe_bootstrapper -->|"should come before"| deployment_manifest
clickonce -->|"uses"| file_patching
clickonce -.->|"requires"| deployment_provider
per_user_deployment -->|"incompatible with"| machine_wide_install
clickonce -->|"recommended for"| per_user_deployment
msi -->|"recommended for"| machine_wide_install
machine_wide_install -.->|"requires"| admin_rights
msix -->|"recommended for"| package_identity
clickonce -->|"not recommended for"| package_identity
clickonce -->|"not recommended for"| windows_service
publish_tool -->|"implements"| clickonce
publish_tool -.->|"requires"| dotnet
dotnet_mage -->|"implements"| deployment_manifest
application_deployment_api -->|"incompatible with"| dotnet
application_deployment_api -->|"requires"| dotnet_framework
publish_tool -->|"uses"| pubxml
offline_availability -.->|"requires"| deployment_provider
clickonce -.->|"automates"| application_settings_migration
self_signed_cert -->|"not recommended for"| clickonce
In the diagram a solid line marks a relation that always holds and a dashed line marks a conditional one (the conditions are given per relation on the detail page). The full list of relations (25 in total, with evidence and certainty) and the definitions of the main concepts are collected on the knowledge map detail page (in Japanese). Data: JSON-LD / Turtle
1. The Conclusion First
In one sentence, ClickOnce is a deployment technology for distributing .NET Windows desktop apps easily on a per-user basis, with automatic updates included.
It fits cases like these.
- Internal line-of-business apps in WinForms / WPF
- You want standard users to be able to install
- Per-user distribution is sufficient
- You want updates built in
- A website or file share is enough as the distribution channel
Conversely, with requirements like these, it is safer to look at other methods from the start.
- Machine-wide install for all users
- Windows services, drivers, in-process shell extensions, heavy COM registration
- Package identity is required
- You want to own update channels, staged delivery, and a custom rollback UX
- The installer carries heavy responsibilities deep inside the OS
In short, ClickOnce is a method that is strong at easy distribution and easy updates, but not suited to projects with heavy OS integration.
First, the positioning in one picture
flowchart TD
A["Want to distribute a Windows app"]
B{"Are there requirements for deep OS integration?"}
C["Start from MSI / MSIX"]
D{"Is it a .NET Windows desktop app where<br/>per-user distribution suffices?"}
E{"Do you want to distribute to standard users?"}
F{"Is the built-in update enough?"}
G["ClickOnce is a strong candidate"]
H["Also compare xcopy / 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 Is ClickOnce?
ClickOnce is Microsoft’s Windows app deployment technology. Officially, it is described as a deployment technology for Windows-based apps that can be installed and run with minimal user interaction and that are self-updating.
The important thing here is not to view ClickOnce as just “a kind of installer.”
In reality, ClickOnce is a deployment model that takes care of all of the following together.
- Which version to distribute
- Which files belong to that version
- How to detect updates
- Where to fetch updates from
- How to keep the app in a safe per-user location
- How to verify integrity at launch
The heart of ClickOnce is not setup.exe itself; it is closer to the essence to see it as a mechanism that manages distribution, updates, and cache management together, centered on manifests.
Even on current .NET, ClickOnce remains a normal candidate. In Visual Studio, the Publish tool is used for .NET Core 3.1 and .NET 5 and later, and when handling manifests manually you use dotnet-mage.exe.
The responsibilities ClickOnce takes care of
flowchart LR
CO["ClickOnce"]
V["Which version to distribute"]
U["Where to fetch updates from"]
S["Keep in a safe per-user location"]
I["Verify integrity and launch"]
CO --> V
CO --> U
CO --> S
CO --> I
3. What Makes Up ClickOnce
The shortcut to understanding how ClickOnce works is to grasp these four pieces.
| Element | Role |
|---|---|
Deployment manifest (.application) |
Describes the version to distribute now, the update location, the update method, etc. |
Application manifest (*.exe.manifest) |
Describes that version’s app binaries, dependent files, hashes, entry point, etc. |
| Application files | exe, dll, config, data files, and so on |
setup.exe (optional) |
A bootstrapper that checks for and installs prerequisites. Used when required runtimes or dependencies exist |
The core here is the two kinds of manifests.
- The deployment manifest expresses “which version is the current right answer for this app”
- The application manifest expresses “what is inside that version”
In other words, ClickOnce’s update decision starts from the deployment manifest, and the application manifest controls what actually gets downloaded.
How the four elements relate
flowchart LR
Setup["setup.exe<br/>optional<br/>check / install prerequisites"]
Deploy["Deployment manifest (.application)<br/>which version to distribute<br/>update location / update conditions"]
App["Application manifest (*.exe.manifest)<br/>contents of that version<br/>file list / hashes / entry point"]
Files["App binaries<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 lead
setup.exe gets a lot of attention, but it is not the lead actor in ClickOnce.
It is a helper that checks for and installs prerequisites.
For example, when the correct .NET runtime or additional redistributable components are needed, setup.exe puts those in place first, and only then does the ClickOnce deployment proper begin.
4. The Flow from Install to Launch
Boldly simplified for practical purposes, the ClickOnce flow looks like this.
- The user opens
setup.exeor the.applicationfile on a web page or file share - In configurations using
setup.exe, prerequisites are checked and any missing ones installed - ClickOnce reads the deployment manifest
- It reads the application manifest the deployment manifest points to
- It fetches the required files and places them into the per-user ClickOnce cache
- In configurations with offline availability, it registers the app in the Start menu / app list
- From then on, the app launches under ClickOnce’s management
The key point is that this is not the mindset of placing files into Program Files like an ordinary installer.
ClickOnce apps go into a safe per-user cache area, isolated per app and per user. This is one of ClickOnce’s defining characteristics.
From install to 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 App binaries
U->>P: Open
Note over U,P: In configurations using setup.exe,<br/>prerequisite checks come first
P->>D: Fetch and read
D->>A: Reference the target version
A->>C: Fetch required files, verify integrity
C->>X: Place and launch
Online-only versus offline-available
ClickOnce offers two broad presentation modes.
- Online-only: runs from the publish location. Feels less like a permanent install
- Offline-available: installed onto the user’s machine and launchable from the Start menu
For internal line-of-business apps, in practice offline-available is the common choice.
flowchart LR
subgraph Online[Online-only]
O1["Launches from the publish location"]
O2["Feels less like a permanent install"]
O3["Tends to assume a network"]
O1 --> O2 --> O3
end
subgraph Offline[Offline-available]
F1["Installed into the user area"]
F2["Registered in the Start menu"]
F3["Launches locally"]
F4["Checks for updates at the configured timing"]
F1 --> F2 --> F3 --> F4
end
5. How Updates Work
ClickOnce’s most obvious strength is, after all, that the update model is built in.
Update decisions start from the deployment manifest
A ClickOnce app reads the deployment manifest and checks:
- Is there a newer version
- Is the update mandatory
- Where to fetch it from
Once an update begins, ClickOnce uses file patching to avoid redundant re-downloads. As a working mental model, it is easiest to think of it as comparing the new version’s application manifest against the current version and fetching only the files that changed.
For thinking about update checks, these three patterns make it easy to organize.
- Check before startup
- Check after startup
- Provide a “check for updates” UI in the app
However, the available APIs and configuration UI differ between .NET Framework and .NET 5+. Do not start implementing based only on memories of old ClickOnce articles.
The update flow
flowchart TD
Start["App launches"]
Check["Check the deployment manifest"]
New{"Is there a newer version?"}
Run["Launch as is"]
Get["Fetch the new version's application manifest"]
Compare["Compare file signatures / hashes"]
Download["Fetch what changed"]
Switch["Materialize the new version and switch"]
Restart["If needed, run the new version after restart"]
Start --> Check --> New
New -- No --> Run
New -- Yes --> Get --> Compare --> Download --> Switch --> Restart
It also helps to keep in mind that, without a network connection, the app simply runs without an update check — knowing this avoids confusion in practice.
Versions are kept in isolation
ClickOnce is less “overwrite the current files in place” and more “fully materialize the new version, then switch over.”
Furthermore, the ClickOnce cache keeps the current version and the previous version separately. This is one of the reasons it rarely pollutes the environment and easily avoids 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
There are two key points here.
- Hard to mix with other users
- Hard to collide with other versions
This structure is a big part of why ClickOnce easily avoids the proverbial DLL Hell.
6. Where ClickOnce Excels
ClickOnce’s virtues go beyond “easy to distribute.” What pays off in practice is roughly this set.
6.1 Easy to distribute to standard users
ClickOnce pairs well with per-user distribution, and the big win is that it is easy to install without administrator privileges.
A common situation with internal line-of-business apps is:
- The users are standard users
- You do not want to file an install request with IT every time
- But you do not want updates to stop
Under these conditions, ClickOnce is quite strong. Its premise — “install into each user’s area, safely, updates included” — matches from the start.
6.2 You do not have to implement updates yourself
Building auto-update from scratch involves more than it looks.
- New-version detection
- Download
- Integrity verification
- Switching from the old version
- Recovery on failure
- Update UI
- Handling the updater itself
ClickOnce covers a large share of this with its existing model.
flowchart LR
subgraph Custom[Responsibilities with a custom updater]
C1["New-version detection"]
C2["Download"]
C3["Integrity verification"]
C4["Switchover"]
C5["Recovery on failure"]
C1 --> C2 --> C3 --> C4 --> C5
end
subgraph Click[Responsibilities you can push onto ClickOnce]
K1["New-version detection"]
K2["Fetch and verify"]
K3["Switchover"]
K1 --> K2 --> K3
end
Of course, you cannot do absolutely anything you like. But the “good-enough updates” that internal apps need are quite easy to satisfy.
6.3 Apps rarely collide with each other
ClickOnce apps are isolated per app, per user, and per version.
That makes the old, familiar failures hard to trigger:
- Version conflicts in shared components
- Overwriting some DLL and breaking another app
- Polluting the environment with manual file swaps
6.4 Easy to ship from Visual Studio
ClickOnce pairs well with Visual Studio’s publish feature, and the short distance from build to distribution is another advantage.
Before diving into a separate discipline like MSI authoring, it is easy to establish the loop of:
- publish first
- distribute first
- get updates flowing first
- get field feedback first
The minimum publish steps
Concepts alone leave the distance too large, so here are the actual steps. For .NET Core 3.1 / .NET 5 and later Windows desktop apps you use the Publish tool, not the old Publish Wizard. It applies to Visual Studio 2019 version 16.8 and later, and to Visual Studio 2022. .NET Framework apps use a different wizard, so their steps differ.
- Right-click the project in Solution Explorer and choose Publish. From the menu bar, it is Build then Publish.
- If a publish profile already exists, the Publish page opens; choose New.
- On the page for choosing the target type, choose Folder.
- On the following Specific target page, choose ClickOnce.
- Enter the publish path, or pick it with Browse. This is where the build output is written.
- On the Install location page, specify where users will install from. It can differ from the output location in step 5, which is the first thing people trip over. Choose a website, a UNC share, or CD / DVD / USB.
- On the Settings page, decide whether offline use is allowed. With offline use enabled, the app appears in the Start menu and updates automatically when you publish a new version. By default, the update source is the same as the install location. To update from somewhere else, specify it in the update settings on this page. The location you specify here becomes the
deploymentProvidercovered in 9.6. - The links at the top of that same Settings page let you specify the files to include in the distribution (Application Files), the prerequisite packages to install (Prerequisites), and other options. The publish version, and whether to bump it automatically on each publish, are also here.
- On the Sign manifests page, specify whether to sign the manifests and which certificate to use. This connects to 9.5.
- On the Configuration page, choose the build configuration, whether the app is framework-dependent or self-contained, and the target runtime identifier.
- Finish saves the profile, and pressing Publish on the Summary page runs the build and the publish. From the second time on, you just press Publish on that page.
Two things are worth knowing in advance for practical work.
- The publish version is independent per ClickOnce profile. If you keep separate profiles for staging and production, you have to manage each one’s version number deliberately.
- The Publish tool creates a publish profile named
.pubxml. When you build from MSBuild on the command line, you point it at that.pubxml. That is the entry point when you put this on CI.
6.5 Settings carry-over is also relatively straightforward
If you use the default application settings provider, ClickOnce has a mechanism to merge the previous version’s settings into the new version at update time.
But note this assumes the default settings provider. With custom settings storage, custom providers, or changed storage locations, it naturally will not work as is.
7. Where It Fits
The projects ClickOnce particularly suits look roughly like these.
| Situation | Why it pairs well with ClickOnce |
|---|---|
| Internal WinForms / WPF line-of-business apps | Standard-user distribution and auto-update mesh well |
| Per-user installation is sufficient | Per-user distribution is natural |
| You want to distribute via a website or UNC share | The distribution channel stays simple |
| Update cadence is roughly weekly to monthly | The built-in update keeps up comfortably |
| You do not want to craft update UI as product value | You can use the existing update model |
Concrete examples with good practical fit:
- Internal data-entry applications
- Desktop business tools for quotes, ordering, inventory, and so on
- Helper apps for configuring equipment
- Internal-only clients distributed to branch offices, factories, and back offices
- Apps that want updates but do not justify building a dedicated updater
For apps like these, keeping distribution and updates simple is itself the value. ClickOnce answers that value directly.
A decision tree for fit
flowchart TD
S["Organize the requirements"]
Q1{"Is it a .NET desktop app such as<br/>WinForms / WPF?"}
Q2{"Is per-user distribution sufficient?"}
Q3{"Do you want standard users to install it?"}
Q4{"Can you distribute via web / file share?"}
Q5{"Is it OK not to over-engineer the update UX?"}
G["ClickOnce is a very strong candidate"]
O["Compare other methods"]
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 It Doesn’t Fit
On the other hand, the situations where you should not force ClickOnce are equally clear.
8.1 A machine-wide install is required
ClickOnce is fundamentally per-user.
- You want to install for all users
- You want to install under
Program Files - You want to deploy and manage at the machine level
In these cases, MSI and friends are more natural than ClickOnce.
8.2 Windows services / drivers / shell extensions / heavy COM registration
These are matters of touching the OS deeply.
- Windows services
- Drivers
- In-process shell extensions
- Configurations that assume systematic COM registration
Once these come in, you have left ClickOnce’s “distribute lightly” worldview.
8.3 You want package identity
One reason to choose MSIX is the requirement of obtaining package identity.
ClickOnce does not go in that direction. If what you want is modern packaging or Windows features that assume package identity, prefer MSIX.
8.4 You want to own the update UX and delivery channels as product
For example:
- stable / beta / preview channels
- Staged delivery
- Adjusting rollout percentages while watching telemetry
- Fine-grained control of background downloads
- A custom rollback strategy
- A complex lifecycle for the updater itself
Once you want all this, ClickOnce’s built-in updates stop being enough.
8.5 Tools where “just drop it in” is enough
Conversely, some cases can be even simpler.
- Drop in the folder and it runs
- Manual file swaps are fine for updates
- Hand it over on a USB stick
- In a closed network where simplicity is the top priority
Here, xcopy distribution can involve even less friction.
Which requirements push you toward other methods
flowchart LR
A1["Install for all users"] --> B1["MSI / sometimes MSIX"]
A2["service / driver / shell extension / heavy COM"] --> B2["MSI / dedicated installer"]
A3["Package identity required"] --> B3["MSIX"]
A4["Staged delivery / channels / custom UX"] --> B4["Custom updater"]
A5["Just dropping it in is enough"] --> B5["xcopy"]
ClickOnce is not all-powerful in either direction; instead, it is a method that is strong on projects of just the right complexity.
9. Common Pitfalls in Practice
ClickOnce is convenient, but going in carelessly causes some stumbles. These in particular are worth grasping in advance.
9.1 Do not view it like “an ordinary installer”
ClickOnce is not a model where files are placed at a fixed install location in a form humans manage directly.
The actual files go into a cache managed by ClickOnce, isolated per version. That makes it a poor match for:
- Operations that assume a fixed EXE path
- Operations that overwrite files directly by hand
- Operations where humans control where the actual files live
ClickOnce is not a method where people manage file placement; it is a method where the deployment state is managed by manifests.
9.2 Many old ClickOnce articles assume .NET Framework
Caution is warranted here.
Even today, search results are full of ClickOnce articles from the .NET Framework era. But on current .NET the situation differs somewhat.
- On .NET Core 3.1 / .NET 5 / .NET 6, the
ApplicationDeploymentAPI cannot be used as is - On .NET 7 and later, some deployment properties can be read via environment variables
- For manual manifest handling,
dotnet-mage.exeis the assumed tool - On the Visual Studio side too, advice assuming the old Publish Wizard may no longer apply directly
Even if you feel you “already know ClickOnce,” it is safer not to implement from old memories.
9.3 Treat prerequisites separately
ClickOnce itself is a deployment model, but the app may need prerequisites to run.
- A supported runtime
- Additional redistributable components
- Other dependencies
This is where the bootstrapper configuration using setup.exe pays off. Leave this fuzzy and you get “we distributed it with ClickOnce, but it doesn’t run.”
9.4 Settings carry-over depends on “what you store and how”
With the default settings provider, settings migration at update time is relatively straightforward. However, with:
- A custom settings provider
- Roaming assumptions
- A self-managed change of the settings storage location
- Large changes to the settings structure between versions
it naturally will not work as is.
9.5 Do not take signing and the update path lightly
ClickOnce has machinery for distribution and updates, but that does not erase your security responsibilities.
Especially in production, it is best to organize up front:
- How the signing certificate is managed
- How the publisher name is presented
- How the update source is managed
- How test self-signing is separated from production signing
flowchart TD
Cert["Code-signing certificate"]
AppMan["Application manifest"]
DepMan["Deployment manifest"]
Verify["Verified on the client"]
Run["Update / run"]
Tamper["Manifest tampering"]
Stop["Stop on verification failure"]
Cert --> AppMan
Cert --> DepMan
AppMan --> Verify
DepMan --> Verify
Verify --> Run
Tamper -. verification fails .-> Stop
“There’s auto-update, so we’re safe” is not the conclusion; what you trust and how that trust is maintained must be considered separately.
9.6 If you move the publish location, revisit deploymentProvider
This one is unglamorous but bites hard in practice.
An installed ClickOnce app looks for updates at the location pointed to by deploymentProvider in the deployment manifest.
That means even if you copy the entire publish folder to a different URL or share, without updating deploymentProvider, clients may keep looking at the original location.
And if you modify a manifest by hand, it must be re-signed.
The 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 at the publish location"]
Client["Clients detect the update"]
Build --> AppManifest --> SignApp --> UpdateDep --> SignDep --> Publish --> Client
In the end, what matters in operating ClickOnce is not so much whether the files were placed as whether the manifests and signatures are consistent.
10. Summary
In one sentence, ClickOnce is
a mechanism for distributing .NET Windows desktop apps easily on a per-user basis, with updates handled at low cost.
Its strengths are mainly these.
- Easy to distribute to standard users
- A built-in update model
- Easy delta-only updates
- Easy isolation of apps and versions
- Easy publishing from Visual Studio
- A good match for internal line-of-business apps
But it is not all-powerful.
- Machine-wide install
- Services / drivers / shell extensions
- Heavy COM registration
- Package identity
- Custom channels or staged delivery
- Crafting the update UX as product value
If you have requirements like these, you should think from the MSI / MSIX / custom-updater side rather than ClickOnce.
ClickOnce is not a lightweight installer that fits everything, but on the projects it suits, it remains quite strong even today.
If what you want to distribute is
- a .NET Windows line-of-business app,
- where per-user installation suffices,
- to standard users,
- without owning updates yourself,
then ClickOnce belongs high on the candidate list.
11. Related Articles
- Choosing a Windows App Distribution Method - MSI/MSIX/ClickOnce/xcopy/Custom Updater
- Security Design for Auto-Update - Why HTTPS Alone Is Not Enough
- When Do You Actually Need Administrator Privileges on Windows? - UAC, Protected Areas, and How to Tell by Design
Related Topics
These topic pages sit close to this theme. Starting from this article, you can move on to related services and other articles.
Windows Technical Topics
An entry point that gathers technical topics on Windows development, bug investigation, and reusing existing assets.
Services Related to This Theme
This article connects to the following service pages. Please enter from whichever is closest.
Windows App Development
For internal line-of-business apps, equipment configuration tools, and modifications to existing software, which of ClickOnce / MSI / MSIX / xcopy has the least friction changes considerably once you work through it before implementation.
Technical Consulting & Design Review
Questions like “Is ClickOnce enough?”, “Should we lean toward MSIX or MSI?”, and “Do we settle for built-in auto-update or own it ourselves?” become much easier to decide when worked through before implementation.
Author Profile
Go Komura
Representative, KomuraSoft LLC
Specializing in Windows software development, technical consulting, and bug investigation, with particular strength in projects involving existing assets and in investigating failures whose causes are hard to see.
12. References
- Microsoft Learn - ClickOnce deployment and security
- Microsoft Learn - ClickOnce for .NET on Windows
- Microsoft Learn - Deploy a .NET Windows Desktop app with ClickOnce
- Microsoft Learn - An overview of Package Identity in Windows apps
- 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.
Windows App Outsourcing and Custom Software Development: What to Sort Out Before You Ask
Before commissioning Windows app outsourcing or custom software development, here is how to sort out existing software modification, devi...
Why Windows Shows "Windows protected your PC"
Why SmartScreen warns when you distribute a Windows app, organized from a practitioner's perspective: code signing, EV/OV certificates, A...
Using WMI/CIM from C# and PowerShell — A Practical Guide to Hardware Info Retrieval, Process Monitoring, and Remote Queries
WMI/CIM is the standard way to get a PC's serial number, monitor free disk space, and detect process launches. This article covers how to...
CI/CD for WinForms / WPF Apps in Practice — Automating from Build to Signing and Distribution with GitHub Actions
A practical guide to setting up CI/CD for WinForms / WPF apps with GitHub Actions. Covers a minimal YAML for build+test on windows-latest...
Preventing Multiple Instances of a Windows App — Named Mutexes and Activating the Existing Window on a Second Launch
This article organizes the classic requirement for business Windows apps — 'don't let the same app launch twice' — around a named Mutex. ...
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.
Frequently Asked Questions
Common questions about the topic of this article.
- What is ClickOnce?
- It is a deployment technology for distributing .NET Windows desktop apps easily on a per-user basis and keeping them updated automatically. Microsoft officially describes it as a technology for deploying Windows-based applications that can be installed and run with minimal user interaction and that update themselves. In practice it is a deployment model that handles distribution, updates, and cache management together with manifests at the center, and the app is kept in a safe per-user cache area, isolated per application, per user, and per version.
- Can I still use ClickOnce going forward? Isn't it old technology?
- ClickOnce is still a normal candidate on current .NET. In Visual Studio, the Publish tool is used for .NET Core 3.1 and .NET 5 and later, and dotnet-mage.exe is the tool for handling manifests by hand. Be aware that the situation differs from the .NET Framework era, though: on .NET Core 3.1, .NET 5, and .NET 6 you cannot use the ApplicationDeployment API as is, and on .NET 7 and later some deployment properties are read through environment variables. It is safer not to start implementing from your memory of older articles.
- What kinds of apps is ClickOnce suited to?
- It fits especially well when you have an internal WinForms or WPF line-of-business app, you want to distribute it to standard users without administrator rights, per-user distribution is enough, and you want updates built in. A website or a file share is enough as the distribution channel. Conversely, it does not fit a machine-wide install for all users, Windows services, drivers, shell extensions, heavy COM registration, requirements that need package identity, or requirements where you want to own update channels and staged delivery; for those, start from MSI, MSIX, or a custom updater.
- How do ClickOnce automatic updates work?
- The update decision starts from the deployment manifest (.application). The app reads the deployment manifest to check whether a newer version exists, whether the update is mandatory, and where to fetch it from. When an update runs, file patching means ClickOnce compares the new version's application manifest against the current version and fetches only the files that changed, avoiding redundant re-downloads. The ClickOnce cache keeps the current version and the previous version separately, and the idea is to materialize the new version correctly before switching over. Without a network connection, the app simply runs without checking for updates.