What ClickOnce Is: How It Works, How Updates Work, and When It Fits or Does Not Fit in Practice

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

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

  1. Table of Contents
  2. 1. The short answer
    • See the positioning on one page first
  3. 2. What ClickOnce is
    • Responsibilities that ClickOnce takes care of
  4. 3. What makes up ClickOnce
    • How the four elements relate
    • setup.exe is a helper, not the main actor
  5. 4. How installation and launch work
    • From installation to the first launch
    • Online-only versus available offline
  6. 5. How updates work
    • Update detection starts from the deployment manifest
    • Update flow
    • Versions are kept separately
  7. 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
  8. 7. Where ClickOnce fits well
    • A decision tree for whether it fits
  9. 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
  10. 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
  11. 10. Summary
  12. 11. Related Articles
  13. Related Topics
    • Windows Technical Topics
  14. Services Connected to This Topic
    • Windows App Development
    • Technical Consulting & Design Review
  15. Author Profile
    • Go Komura
  16. 12. References

Table of Contents

  1. The short answer
  2. What ClickOnce is
  3. What makes up ClickOnce
  4. How installation and launch work
  5. How updates work
  6. What ClickOnce does especially well
  7. Where ClickOnce fits well
  8. Where ClickOnce does not fit well
  9. Common practical pitfalls
  10. Summary
  11. Related Articles
  12. 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:

  1. The user opens setup.exe or .application from a web page or a file share
  2. If the deployment uses setup.exe, prerequisites are checked and missing ones are installed
  3. ClickOnce reads the deployment manifest
  4. It reads the application manifest referenced by the deployment manifest
  5. Required files are obtained and placed into the per-user ClickOnce cache
  6. If the configuration allows offline use, the app is registered in the Start menu or app list
  7. 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 ApplicationDeployment API 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.exe becomes 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.

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.

View the service Contact

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.

View the service Contact

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.

View profile Contact

12. References

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