Choosing a Windows App Distribution Method - MSI/MSIX/ClickOnce/xcopy/Custom Updater
· Updated: · Go Komura · Windows, Deployment, MSI, MSIX, ClickOnce, xcopy, Updater
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.21614556)
- First published
Cite this article(DOI: 10.5281/zenodo.21614555)
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). Choosing a Windows App Distribution Method - MSI/MSIX/ClickOnce/xcopy/Custom Updater. KomuraSoft LLC. https://doi.org/10.5281/zenodo.21614555 https://comcomponent.com/en/blog/2026/03/20/000-windows-app-deployment-msi-msix-clickonce-xcopy-custom-updater/
- DOI (latest version)
- 10.5281/zenodo.21614555
- DOI (this version)
- 10.5281/zenodo.22217182
Download the Excel decision worksheet with Japanese and English sheets
When deciding how to distribute a Windows app, it is tempting to start the conversation with “which is newest” or “which is easiest.” But what actually matters in practice are different axes.
- Do you want to install per user, or machine-wide?
- Do you want to delegate updates to a distribution platform, or own them yourself?
- Is there OS integration such as services / drivers / shell extensions / COM registration?
- Does it need to survive air-gapped, offline, or USB distribution?
- Do you need package identity, or do you want to run as plain, unrestricted Win32?
Choosing a distribution method is not a matter of installer-format preference - it is a choice of how deeply you touch the OS and who owns update responsibility.
flowchart TB
accTitle: The two axes that decide a distribution method
accDescr: A diagram showing that the choice of distribution method is not the installer-format preference of which is newest or easiest, but a choice along two axes, namely how deeply the app touches the OS and who owns update responsibility.
a0["Which is newest or easiest"] -.-> a1["Not decided on this axis"]
a2["How deeply you touch the OS"] --> a4["The distribution method follows"]
a3["Who owns update responsibility"] --> a4
Figure 1: The distribution method is decided by the depth of OS integration and by update responsibility, not by preference.
This article is written for developers who are building a Windows desktop app and are about to choose a distribution method, or want to revisit the one they have, and for the IT staff who take over its operation. It assumes no particular language or framework. This field carries a lot of terminology that circulates in English as-is, so those terms are collected in 1.1. The contents of the worksheet linked at the top are summarized in 1.2.
1. The Conclusion First
Putting it roughly, but in a form that is useful in practice:
- If you install machine-wide, register services or COM, or need to install prerequisites, start your thinking from MSI
- If you assume Windows 10/11 and want clean install / clean uninstall, frequent updates, and package identity, MSIX is a strong candidate
- If you want to distribute an internal .NET desktop app per user, easily, with auto-update, ClickOnce is still remarkably strong
- If you prioritize drop-in tools, air-gapped networks, USB distribution, and no administrator rights, xcopy is the most straightforward
- If you want to own the update UX, channels, staged rollout, telemetry, and recovery strategy yourselves, that is a custom updater
- If you need a driver, it is safer not to center your thinking on MSIX from the start
- If you need an in-process Explorer shell extension, first check what MSIX can cover and the OS version conditions
Bluntly summarized:
- Heavy OS registration → lean MSI
- Want package identity and modern packaging → MSIX
- Want easy per-user distribution and built-in updates → ClickOnce
- Drop-in distribution is the top priority → xcopy
- Prepared to design and operate your own update infrastructure → custom updater
flowchart TB
accTitle: A blunt summary of the five methods
accDescr: A diagram showing that heavy OS registration leans toward MSI, wanting package identity and modern packaging points to MSIX, wanting easy per-user distribution with built-in updates points to ClickOnce, prioritizing drop-in distribution points to xcopy, and being prepared to design and operate your own update infrastructure points to a custom updater.
b1{"Heavy OS registration"} -->|"Yes"| b2["Lean MSI"]
b1 -->|"No"| b3{"Want package identity"}
b3 -->|"Yes"| b4["MSIX"]
b3 -->|"No"| b5{"Easy per-user distribution plus auto-update"}
b5 -->|"Yes"| b6["ClickOnce"]
b5 -->|"Drop-in is the top priority"| b7["xcopy"]
b7 -.-> b8["Custom updater if you are ready to own the update infrastructure"]
Figure 2: When in doubt, work through depth of registration, then identity, then ease of distribution.
1.1 Terms Used in This Article
A lot of distribution terminology circulates in English as-is, so here it is up front.
| Term | In plain English | Meaning |
|---|---|---|
| package identity | Package ID | The unique identity the OS assigns to a packaged app. Some Windows features cannot be used without it |
| authoring | Creating the installer | The work of defining what goes into an MSI. Used in roughly the sense of “writing an MSI” |
| custom action | Custom step | A mechanism for injecting your own code where the installer’s standard behavior is not enough |
| ARP | The app list | Short for Add / Remove Programs. The list shown under Installed apps in Settings, or Programs and Features in Control Panel |
| clean install / clean uninstall | Clean installation / removal | A state where everything installs completely and nothing is left behind when it is removed |
| repair | Repair | Restoring a broken installation through the installer’s own machinery |
| telemetry | Usage measurement | A mechanism for collecting and understanding update outcomes and usage |
| per-user / per-machine | Per user / per machine | Whether it is installed for that one user only, or shared by all users |
| shell extension | Explorer extension | A component built into Explorer, such as a right-click menu entry or an icon overlay |
| unrestricted | No restrictions | Free to touch files and the registry as plain Win32, without package restrictions |
| side-by-side | Coexistence | Keeping multiple versions on the same machine at once |
| staged rollout | Phased delivery | Rolling out a new version to a controlled percentage of users rather than everyone at once |
1.2 What Is in the Worksheet Linked at the Top
The Excel worksheet at the top of this article exists so you can apply the decisions in this article to your own project and record them. It comes in a Japanese and an English version, each with two sheets.
The Planner sheet is divided into three blocks.
- Input sheet: fill in the following seven items and you end up with a place to record a first choice and the reasoning behind it
- Distribution scope - per-user / per-machine / both / undecided
- OS integration elements - none / service / driver / shell extension / COM registration / several
- package identity - required / not required / cannot tell yet
- Standard-user installation requirement - mandatory / not needed / depends
- Update frequency - manual or rare / monthly / weekly / more often
- Target environment - air-gapped or offline / managed recent Windows / a mix that includes older Windows / USB and on-site
- App type notes - internal .NET desktop / commercial product / utility / mixed
- How to tell the candidates apart: for each of the five methods, the conditions that make it a strong first look and the conditions that rule it out early
- The decision flow: what order to read the items above in, and which method the result tends to point to
The Reference sheet carries the decision table from section 3 and the comparison table from section 4 of this article as they are.
In other words, it turns sections 3, 4, and 7 of this article into something you can fill in per project. If reading is enough to reach a conclusion, there is no need to download it. Use it when you want to compare several projects, or to leave a record inside your organization of why a decision was made.
flowchart TB
accTitle: How to use the worksheet
accDescr: A diagram showing the flow of a worksheet that turns the decision into a per-project record, where you fill in the seven items on the Planner sheet, narrow the candidates and lean toward a method with the decision flow, and record the first choice and the reason.
c1["Fill in the 7 items on the input sheet"] --> c2["Narrow down with the candidate signals"]
c2 --> c3["Lean toward a method with the decision flow"]
c3 --> c4["Record the first choice and the reason"]
c4 -.-> c5["The Reference sheet holds the tables from sections 3 and 4"]
Figure 3: The worksheet turns the article’s decision into a record kept per project.
Knowledge map for this article
The deployment method for a Windows app is chosen not by a preference for an installer format but along two axes: how deeply the product integrates with the OS, and which side holds responsibility for updates. MSI suits installations that touch the OS deeply, such as Windows services, COM registration, drivers, and shell extensions, but it has no package identity, while MSIX implements package identity and delivers a clean install and clean updates yet is basically unsuited to drivers and shell extensions. ClickOnce can deploy a .NET app per-user and update it automatically with little effort but does not suit a product that includes a Windows service, and xcopy deployment has the simplicity of running as soon as the files are placed, at the cost of having no package identity and no affinity with services. A custom updater is the choice that takes on signature verification and code signing certificate management in-house in exchange for freedom in how updates work and the ability to handle deployment on isolated networks.
flowchart LR
accTitle: Deployment methods for Windows apps
accDescr: Diagram showing how MSI, MSIX, ClickOnce, xcopy, and a custom updater are chosen between along two axes: the depth of OS integration and which side holds responsibility for updates.
msi["MSI (Windows Installer)"]
msix["MSIX"]
clickonce["ClickOnce"]
windows_service["Windows Service"]
driver_package["Driver Package"]
shell_extension["Shell Extension (Explorer Extension)"]
com["COM (Component Object Model)"]
closed_network["Closed Network"]
package_identity["Package Identity"]
code_signing_cert["Code signing certificate"]
dotnet[".NET (Core and Later)"]
xcopy_deployment["xcopy Deployment"]
custom_updater["Custom updater"]
msi -->|"recommended for"| windows_service
msi -->|"recommended for"| driver_package
msi -->|"recommended for"| shell_extension
msi -.->|"uses"| com
msi -->|"recommended for"| closed_network
msix -->|"implements"| package_identity
msix -->|"not recommended for"| driver_package
msix -.->|"not recommended for"| shell_extension
msix -.->|"recommended for"| closed_network
msix -->|"requires"| code_signing_cert
clickonce -.->|"requires"| dotnet
clickonce -.->|"recommended for"| closed_network
clickonce -->|"not recommended for"| windows_service
xcopy_deployment -->|"not recommended for"| windows_service
xcopy_deployment -->|"recommended for"| closed_network
custom_updater -.->|"requires"| code_signing_cert
custom_updater -.->|"recommended for"| closed_network
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 (17 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
2. The Five Are Not on the Same Playing Field
This part really matters.
MSI / MSIX / ClickOnce / xcopy are mainly about how to install. A custom updater, on the other hand, is mainly about how to own update responsibility.
So in practice, it is easier to think in two layers.
| Layer | Main candidates | What to decide |
|---|---|---|
| Initial installation | MSI / MSIX / ClickOnce / xcopy | Where to place files, what to register, privileges, uninstall |
| Ongoing updates | MSIX App Installer / ClickOnce / manual replacement / custom updater | Update checks, delivery source, signature verification, rollback, channels, UI |
Drawn out, it looks like this. The dotted lines mean “the update path that follows naturally from that installation method.”
flowchart TB
APP["Windows app to distribute"] --> Q1["First: how to install<br/>Initial installation layer"]
APP --> Q2["Next: who owns update responsibility<br/>Ongoing update layer"]
Q1 --> MSI["MSI"]
Q1 --> MSIX["MSIX"]
Q1 --> CO["ClickOnce"]
Q1 --> XC["xcopy"]
Q2 --> AI["MSIX App Installer"]
Q2 --> COU["ClickOnce built-in updates"]
Q2 --> MAN["Manual replacement"]
Q2 --> OWN["Custom updater"]
MSIX -.-> AI
CO -.-> COU
MSI -.-> MAN
XC -.-> MAN
MSI -.-> OWN
XC -.-> OWN
Figure 4: The two-layer model of initial installation and ongoing updates. Dotted lines are the update paths that follow naturally.
With ClickOnce and MSIX, deciding the upper layer largely decides the lower one as well. With MSI and xcopy, the lower layer has to be decided separately. “What do we do about updates” is most likely to be left hanging when you pick one of those two.
So it keeps you grounded to think of a custom updater not as something you pick first, but as something you add when an existing distribution method cannot meet your update requirements.
flowchart TB
accTitle: Updates are left hanging with MSI and xcopy
accDescr: A diagram showing that choosing ClickOnce or MSIX largely settles the update path as well, while choosing MSI or xcopy leaves the ongoing update layer to be decided separately, and a custom updater is added on top when those update requirements are not met.
d1["Choose ClickOnce / MSIX"] --> d2["The update path is largely settled too"]
d3["Choose MSI / xcopy"] --> d4["How to update is left hanging"]
d4 --> d5["Decide the ongoing update layer separately"]
d5 -.-> d6["Add a custom updater when that is not enough"]
Figure 5: A custom updater is not the first option but an addition that fills a gap in the update layer.
3. The One-Page Decision Table
First, here is the most usable decision table.
| Situation | First choice | Why |
|---|---|---|
| For all users, with services, COM registration, machine-wide settings | MSI | Playing on Windows Installer’s home turf means less goes wrong |
| Windows 10/11 assumed; want clean install / uninstall, frequent updates, package identity | MSIX | Easy to lean on modern packaging and the update model |
| Want to easily distribute an internal .NET business app per user | ClickOnce | The built-in update model is easy to use |
| Drop-in tools, air-gapped, USB, no administrator rights | xcopy | Brings as little of the “install” concept as possible |
| Commercial product where you want to own the update UX and channels | Custom updater | More freedom than built-in updates |
| Driver required | Lean MSI or a dedicated installer | Driver packages are a separate problem; MSIX is a poor fit |
| In-process shell extension required | Lean MSI or a dedicated installer | On Windows 11 21H2 and later, MSIX can register legacy context menu handlers and the like, but the conditions need checking |
The most important thing in this table is not jumping to a custom updater just because “there are updates.”
4. Comparison by Criterion
| Criterion | MSI | MSIX | ClickOnce | xcopy | Custom updater |
|---|---|---|---|---|---|
| Ease of per-user installation | Good | Good | Excellent | Excellent | Good |
| Ease of per-machine installation | Excellent | Good | Weak | No | Good |
| Built-in updates | Weak | Excellent | Excellent | No | Excellent |
| Package identity | No | Excellent | No | No | No |
| Fit with services | Excellent | Weak | No | No | Good |
| Fit with drivers | Weak | No | No | No | Good |
| Fit with shell extensions | Excellent | Weak | No | No | Good |
| Air-gapped / offline distribution | Excellent | Good | Good | Excellent | Excellent |
| Implementation / operations cost | Low | Low | Very low | Very low | High |
| Freedom in update UX | Weak | Good | Weak | No | Excellent |
What to look for in this table is not which is strongest, but which has the least friction.
5. What Kinds of Projects Each Is Suited To
5.1 MSI
MSI is the reference point when you want to properly install / uninstall / repair a traditional Windows desktop app.
It is especially well suited to projects like these.
- Business apps for all users
- Apps that include a Windows service
- Apps involving COM registration, file associations, or machine-wide settings
- Products with an existing installer operation already in place
MSI’s strength is that it lets you express “how the app was installed into the OS” in Windows’ own idiom.
Its weaknesses are equally clear.
- Authoring is quietly difficult
- Sloppy upgrade / patch design tends to hurt later
- The more custom actions you add, the more fragile it becomes
- For frequently updated products, the update UX tends to get heavy
flowchart TB
accTitle: What MSI gives and what it costs
accDescr: A diagram showing that MSI makes it easy to express how an app was installed into the OS in the Windows idiom, while authoring is quietly difficult, the product grows more fragile as custom actions pile up, and the update UX tends to get heavy for frequently updated products.
e1["MSI"] --> e2["Expresses installation into the OS in the Windows idiom"]
e2 --> e3["install / uninstall / repair all covered"]
e1 -.-> e4["Authoring is quietly difficult"]
e4 -.-> e5["The more custom actions, the more fragile"]
Figure 6: MSI trades the difficulty of authoring for expressive power over OS integration.
5.2 MSIX
MSIX is the choice when you want modern packaging and clean update / uninstall. It also gains a lot of significance when you want to use Windows features that require package identity.
It is suited to cases like these.
- Desktop apps that can assume Windows 10/11
- Business apps with a higher update cadence
- Apps that want Windows features where package identity matters
- Projects leaning on Intune or App Installer
MSIX’s strength is the cleanliness of updates and uninstallation.
But not everything fits. These four points in particular are safer to check first.
- In-process shell extensions (MSIX on Windows 11 21H2 and later can register legacy context menu handlers and the like, but the manifest declaration and the target OS need verifying)
- Drivers
- Old, unrestricted Win32 assumptions
- Configurations where you do not want package identity
Each of these four is settled by a different document. Rather than stopping at “MSIX apparently cannot do it,” it is faster to decide up front which reference will settle the question.
| What you want to check | Document to read | What it tells you |
|---|---|---|
| From which Windows version a feature is available | Microsoft Learn, “MSIX features and supported platforms” | A table of supported OS versions per feature |
| Whether an in-process shell extension can be registered | Microsoft Learn, “Support legacy context menus for packaged apps” | The supported OS versions and how to declare it in the manifest |
| Whether your installer can be turned into MSIX | Microsoft Learn, “Prepare to package a desktop application” and “Know your installer” | A list of configurations that cannot be packaged, and what to check beforehand |
| What happens to a configuration that includes services | Microsoft Learn, “Convert an installer that includes services” | The conditions and limits for converting an installer with services |
Links to all of them are in the references in section 9. When making the decision, look not for “is it supported” but for “from which version, and with which declaration, does it become supported.” Miss the OS version conditions here and it comes back later in the form of an app that ran on the test machine but will not install on the older Windows machines in the field.
flowchart TB
accTitle: Settle MSIX limits down to the reference that answers them
accDescr: A diagram showing that the four MSIX uncertainties such as shell extensions and drivers are each answered by a different reference, so instead of stopping at it seems impossible you check from which version and with which declaration support begins, which prevents the case that works on the test machine but fails in the field.
f1["The 4 MSIX uncertainties"] --> f2["Do not stop at it seems impossible"]
f2 --> f3["Decide which reference settles it"]
f3 --> f4["Check from which version and with which declaration"]
f4 -.-> f5["Prevent works on the test machine, fails in the field"]
Figure 7: Settle MSIX limits by checking the OS version conditions and the declaration method.
5.3 ClickOnce
ClickOnce is still remarkably strong when you want to run an internal .NET desktop app per user, quickly, updates included.
It suits scenarios like these.
- Internal business apps
- You want standard-user installation
- Per-user distribution is sufficient
- You do not want to invest heavily in the update UX
Conversely, it is safer not to expect it to handle products that touch the OS deeply, or to play the installer-like role of bundling multiple prerequisites.
5.4 xcopy
xcopy is deploy, not install. There is no registry registration, no repair feature, no package identity. In exchange, if dropping files in place is enough, it is about as simple as it gets.
It shines for tools like these.
- Diagnostic tools
- Equipment configuration tools
- Log collection tools
- Utilities handed to a site on a USB stick
- Cases where you want multiple versions side by side
xcopy’s strength is that its failure modes are easy to understand. Replace the whole folder; if you want to go back, return to the previous version - that kind of operation is easy.
flowchart TB
accTitle: xcopy is deploy, not install
accDescr: A diagram showing that xcopy has no registry registration, no repair feature, and no package identity, and in exchange it only needs the files dropped in place, so updating means replacing the whole folder and rolling back means restoring the previous version, which makes its failure modes easy to understand.
g1["Drop in the whole folder"] --> g2["It just runs"]
g2 --> g3["Update by replacing the whole folder"]
g3 --> g4["Roll back by restoring the previous version"]
g1 -.-> g5["No registration, no repair, no identity"]
Figure 8: The value of xcopy is that installation, updating, and rolling back are all simple.
But of course it has weak spots.
- Start menu / ARP / repair
- File associations / services / shell extensions / drivers
- Built-in updates
5.5 Custom updater
A custom updater is less a choice of freedom than a choice of responsibility.
It becomes worth considering when you have requirements like these.
- High update frequency
- You want channels such as stable / beta / preview
- You want to control staged delivery and rollout percentages
- You want fine control over background downloads, notifications, and maintenance windows
- You want your own update telemetry and crash recovery
The strengths are big, but so is what you pay.
- Signature verification
- A delivery manifest
- Retry / resume
- Proxy / firewall / air-gapped support
- Rollback
- Recovery from broken updates
- Updating the updater itself
In other words, what increases is not freedom but responsibility.
flowchart TB
accTitle: A custom updater is a choice of responsibility
accDescr: A diagram showing that a custom updater buys freedom such as channels, staged delivery, and telemetry, in exchange for taking on the design and operation of signature verification, delivery manifests, rollback, recovery from broken updates, and updating the updater itself.
h1["Gains: channels, staged delivery, telemetry"] --> h3["Custom updater"]
h2["Costs: signature verification, rollback, recovery"] --> h3
h3 --> h4["What increases is responsibility, not freedom"]
h2 -.-> h5["Updating the updater itself is your job too"]
Figure 9: What a custom updater adds is not freedom but responsibility for running update infrastructure.
5.6 What to Look Into Once the Method Is Decided
Deciding “we are going with MSI” still stalls if you do not know what to look into next. Here are the usual entry points. None of these is a “use this” recommendation - they are the names worth knowing once you have chosen that method.
| Method chosen | What to look into next | Notes |
|---|---|---|
| MSI | WiX Toolset | An open source toolset for writing MSI in XML. The standard entry point into MSI authoring |
| MSI | Advanced Installer, InstallShield | Commercial, GUI-centric MSI authoring tools. For designing custom actions and upgrades through a GUI |
| An EXE is fine, it does not have to be MSI | Inno Setup, NSIS | Tools that build EXE installers in their own format rather than MSI. They do not play on Windows Installer’s turf |
| MSIX | MSIX Packaging Tool, makeappx.exe, signtool.exe |
The conversion tool for existing installers, plus the Windows SDK packaging and signing tools |
| MSIX | Windows Application Packaging Project | The Visual Studio project type that turns an existing project into MSIX |
| ClickOnce | The Visual Studio publish wizard, mage.exe |
Publishing and manifest generation. Update behavior is decided by the options set at publish time |
| Custom updater | Squirrel.Windows, Velopack, WinSparkle, NetSparkle | Libraries that give you the skeleton of an updater. Before deciding whether to adopt one, compare them on how they handle signature verification and rollback |
The thing to watch here is that choosing a tool and choosing a method are two different decisions. Inno Setup, for example, is easy to work with, but what it produces is not an MSI, so it does not fit operations that assume Windows Installer - software deployment through Group Policy, or repair via msiexec. If that is exactly why you chose MSI in 5.1, the tool has to match.
flowchart TB
accTitle: Choosing a tool is not choosing a method
accDescr: A diagram showing that Inno Setup is easy to work with but does not produce an MSI, so it does not support software deployment through Group Policy or repair via msiexec, and the tool therefore has to match the reason the method was chosen.
i1["Decide the method"] --> i2["Decide the tool"]
i2 -.-> i3["Inno Setup does not produce an MSI"]
i3 -.-> i4["No GPO deployment or msiexec repair"]
i4 -.-> i5["Match the tool to the reason for the method"]
Figure 10: A convenient tool does not necessarily play on the turf of the method you chose.
6. The Points People Get Stuck On
6.1 Do you need package identity?
If what you want is a Windows feature that presumes package identity, the value of MSIX shoots up.
Conversely, if you want
- unrestricted file system access
- unrestricted registry access
- freedom in elevation / process model
- to keep old Win32 assumptions as they are
then unpackaged-style methods are the more natural fit.
flowchart TB
accTitle: Split the decision on whether package identity is needed
accDescr: A diagram showing that wanting a Windows feature that presumes package identity makes MSIX far more valuable, while wanting unrestricted file and registry access or wanting to keep old Win32 assumptions as they are makes unpackaged-style methods the natural fit.
j1{"Want features that presume package identity"} -->|"Yes"| j2["The value of MSIX shoots up"]
j1 -->|"Want to run unrestricted"| j3["Unpackaged-style methods are natural"]
Figure 11: Whether identity is needed is the watershed between packaged and unpackaged.
6.2 Do you have services / drivers / shell extensions?
These three make the distribution method heavier at a stroke.
- Driver: a poor fit for MSIX
- In-process shell extension: a poor fit for MSIX
- Windows service: natural with MSI; MSIX is also a candidate under certain conditions
The more deeply OS-coupled elements you have, the more the main subject shifts from distribution that looks easy to whether you can install, update, and remove it correctly.
6.3 Per-user or per-machine?
Proceed with this left vague and you will fight about it later, guaranteed.
- Leaning per-user
- ClickOnce
- xcopy
- Some MSIX
- Leaning per-machine
- MSI
- MSIX when the conditions fit
“We want to install without administrator rights” and “we want all users to use it from the same location” are not the same thing.
flowchart TB
accTitle: Do not conflate per-user and per-machine
accDescr: A diagram showing that leaning per-user points to ClickOnce, xcopy, or some MSIX, leaning per-machine points to MSI or MSIX when the conditions fit, and wanting to install without administrator rights is not the same thing as wanting all users to work from one shared location.
k1["Leaning per-user"] --> k2["ClickOnce / xcopy / some MSIX"]
k3["Leaning per-machine"] --> k4["MSI / MSIX when conditions fit"]
k1 -.-> k5["Installing without rights and one shared location are different things"]
Figure 12: Leave the installation scope vague and it will cause an argument later.
6.4 Update frequency and operational responsibility
Viewed through update cadence, roughly:
- Quarterly to monthly updates: MSI is perfectly workable
- Monthly to weekly updates: MSIX / ClickOnce are considerably easier
- Weekly to daily updates: reasons to consider a custom updater emerge
- Manual updates are fine / the deploying side controls them: xcopy is enough
A distribution method is operations design as much as it is technology selection.
flowchart TB
accTitle: The update frequency staircase
accDescr: A diagram showing rough guidance on update frequency, where quarterly to monthly runs fine on MSI, monthly to weekly is much easier on MSIX or ClickOnce, weekly to daily gives reasons to consider a custom updater, and manual updates are fine on xcopy.
m1["Quarterly to monthly: MSI is enough"] --> m2["Monthly to weekly: MSIX / ClickOnce are easier"]
m2 --> m3["Weekly to daily: reasons for a custom updater appear"]
m1 -.-> m4["If manual updates are fine, xcopy is enough"]
Figure 13: The higher the update frequency, the more built-in updates or your own infrastructure are worth.
6.5 Air-gapped and offline distribution
In air-gapped environments, simplicity often beats elegant auto-update.
- xcopy is strong
- MSI is also strong
- ClickOnce also works via file shares or removable media
- MSIX can also work depending on how you use App Installer
But if you update frequently in an air-gapped environment, then unless you also decide “who places the new version where, and how old versions are retained,” the operation tends to fall apart no matter which method you pick.
flowchart TB
accTitle: Simplicity wins in air-gapped environments
accDescr: A diagram showing that in air-gapped environments simplicity often beats elegant auto-update, and that with frequent updates the operation falls apart unless you also decide who places the new version where and how old versions are retained.
n1["Air-gapped or offline environment"] --> n2["Simplicity over elegant auto-update"]
n2 --> n3["xcopy and MSI are strong"]
n2 -.-> n4["Decide who places the new version where"]
n4 -.-> n5["Decide how old versions are retained"]
Figure 14: In air-gapped environments, settle how new and old versions are placed before picking a method.
7. The Final Six Questions When You Are Stuck
- Is the app for the current user only, or does it need to be installed machine-wide?
- Are there services / drivers / shell extensions / COM registration?
- Will you use Windows features that require package identity?
- Do you want installation by standard users only?
- Is the update cadence monthly, weekly, or higher?
- Is the target environment air-gapped, and are the OS versions uniform?
Just answering these six usually reveals the landing zone.
- 2 is “yes” → start from the MSI side
- 3 is “yes” → consider MSIX first
- 1 is current user, 4 is “yes”, and it is a .NET desktop app → ClickOnce is a strong candidate
- 4 is “yes”, 2 is “no”, and drop-in operation suffices → xcopy is a strong candidate
- 5 is high and you want to own the update UX as part of the product’s value → put a custom updater on the comparison list
flowchart TB
accTitle: Where the six questions land
accDescr: A diagram showing the landing zones, where OS integration such as a service points to the MSI side first, needing package identity puts MSIX first, a current-user .NET desktop app installed by standard users points to ClickOnce, drop-in operation points to xcopy, and a high update frequency with a desire to own the update UX puts a custom updater on the comparison list.
p1{"OS integration such as a service"} -->|"Yes"| p2["Start from the MSI side"]
p1 -->|"No"| p3{"Package identity required"}
p3 -->|"Yes"| p4["Consider MSIX first"]
p3 -->|"No"| p5{"Per-user plus standard-user installation"}
p5 -->|"If .NET desktop"| p6["ClickOnce is a strong candidate"]
p5 -->|"If drop-in operation"| p7["xcopy is a strong candidate"]
p6 -.-> p8["Also compare a custom updater if you want to own the update UX"]
Figure 15: Follow the six answers in this order and the landing zone is usually visible.
8. Summary
Windows app distribution largely condenses to this one statement:
Decide separately how to make initial installation work and who owns the responsibility for running ongoing updates.
On top of that, the rough practical judgments are:
- MSI: traditional desktop apps that go deep into the OS
- MSIX: apps that want package identity and modern packaging / updates
- ClickOnce: easily distributing and updating per-user .NET business apps
- xcopy: self-contained tools where dropping files in place is enough
- Custom updater: products whose teams are prepared to design and operate updates themselves
And the most important points are these.
- If you have drivers / shell extensions / services, the distribution method is decided by the OS integration approach, not the final appearance
- If you need package identity, MSIX carries a lot of weight
- A custom updater is the last resort, not the first option
- In air-gapped environments, simplicity often beats cleverness
If you are stuck, pinning down even just these three first - per-user or per-machine, what gets registered with the OS, and how frequent updates are - moves the conversation a long way forward.
flowchart TB
accTitle: The three to pin down first
accDescr: A diagram showing that if you are stuck, pinning down just three things first, whether it is per-user or per-machine, what gets registered with the OS, and how frequent updates are, moves the distribution discussion a long way forward.
q1["Per-user or per-machine"] --> q4["Pin these down first"]
q2["What gets registered with the OS"] --> q4
q3["How frequent updates are"] --> q4
q4 --> q5["The conversation moves a long way forward"]
Figure 16: When the method is unclear, pin down at least these three first.
9. References
- Microsoft Learn, Windows Installer
- Microsoft Learn, What is MSIX?
- Microsoft Learn, Packaging overview for Windows apps
- Microsoft Learn, MSIX features and supported platforms
- Microsoft Learn, Support legacy context menus for packaged apps
- Microsoft Learn, App Installer file overview
- Microsoft Learn, Prepare to package a desktop application
- Microsoft Learn, Know your installer
- Microsoft Learn, Convert an installer that includes services
- Microsoft Learn, ClickOnce deployment and security
- Microsoft Learn, Manage updates for a ClickOnce application
- Microsoft Learn, Choosing a ClickOnce deployment strategy
- Microsoft Learn, ClickOnce cache overview
- Microsoft Learn, Windows App SDK deployment guide for self-contained apps
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
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...
What Is ClickOnce? - How It Works, How It Updates, and Where It Fits (and Doesn't) in Practice
An overview of ClickOnce, the deployment technology used for .NET Windows desktop apps - manifests, updates, the cache, signing, and whic...
Security Design for Auto-Update - Why HTTPS Alone Is Not Enough
We treat auto-update as a trust boundary and walk through signed metadata, client-side verification, key separation, rollback protection,...
Windows Shell Integration Today — Context Menus, File Associations, and What Changed in Windows 11
Why a Windows 11 context menu hides items behind "Show more options", explained from the extension → ProgID → verb association basics thr...
AppLocker, App Control for Business (WDAC), and Business App Distribution — Before "Application Control" Blocks You
Explains the differences between AppLocker, App Control for Business (formerly WDAC), and Smart App Control, and sets out what developers...
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
For Windows app distribution, the method has to be chosen with services, drivers, WebView2, WinUI, and enterprise operations in mind, so sorting things out before implementation pays off.
Technical Consulting & Design Review
MSI / MSIX / ClickOnce / xcopy / custom updaters are a matter of update responsibility and OS integration design, not installer preference, so revisiting the requirements breakdown makes the decision much easier.
Frequently Asked Questions
Common questions about the topic of this article.
- What is the difference between MSI and MSIX?
- MSI is the traditional Windows installer format. It fits installations that reach deep into the OS - per-machine installation, Windows services, COM registration, shell extensions - and it lets you express install, uninstall, and repair in Windows' own idiom. MSIX is modern packaging that assumes Windows 10/11, and its strengths are clean install, clean uninstall, frequent updates, and package identity. On the other hand, MSIX is a poor fit for drivers, in-process shell extensions are only conditionally supported from Windows 11 21H2 onward, and it does not suit old, unrestricted Win32 assumptions. If registration with the OS is heavy, start from MSI; if you want package identity and clean updates, start from MSIX.
- Should I choose MSIX or ClickOnce?
- If you want to distribute a per-user internal .NET business app easily with auto-update, ClickOnce is still a remarkably strong choice. Its built-in update model is easy to use, it installs as a standard user, and you do not have to build an update UX yourself. MSIX, on the other hand, is the stronger candidate when you need Windows features that require package identity, when clean install and uninstall matter, or when you want to lean on Intune or App Installer. Neither suits products that touch the OS deeply, so if you have services or drivers, think from the MSI side.
- Is ClickOnce still usable, or is it obsolete technology?
- It is still usable, and where it fits it is a remarkably strong option. It works well when you want to distribute an internal .NET desktop app per user, quickly, at standard-user privilege, and run it on the built-in update model. Conversely, it is safer not to expect it to handle products that touch the OS deeply - Windows services, drivers, shell extensions - or to play the installer-like role of bundling several prerequisites. In terms of update frequency, monthly to weekly updates run quite comfortably on ClickOnce or MSIX.
- When should I consider a custom updater?
- A custom updater is not something you pick first. It is something you add when an existing distribution method cannot meet your update requirements. It becomes worth considering when update frequency is high, when you want channels such as stable, beta, and preview, when you want to control staged delivery and rollout percentages, or when you want to watch update telemetry and crash recovery yourself. In exchange you take on the design and operation of signature verification, delivery manifests, retries, rollback, recovery from broken updates, and updating the updater itself - so treat it as a choice that increases responsibility rather than freedom.