Skip to content
desktop

When the Desktop Still Wins

AYA · Published February 26, 2026

The web won. We all know this. Browsers handle video editing, 3D rendering, IDE-quality code editors, and collaborative document workflows that would have seemed absurd on a web page ten years ago. And yet: a meaningful class of software problem still belongs on the desktop, and gets it wrong when it doesn’t.

This is not nostalgia. It is an engineering argument.


The cases where the desktop is the right answer

Three categories come up repeatedly in serious software decisions.

Long, uninterrupted work sessions. A browser tab is fragile. It can be closed by accident, throttled by the OS, killed by the browser’s memory manager, or interrupted by an extension. For work that unfolds over hours (medical imaging review, financial modeling, CAD design, legal document analysis), the application must be stateful, resilient, and always present at the exact point the user left it. A native window process managed by the OS survives this. A tab does not.

Large local data. When the data set is measured in gigabytes and the user needs to query, filter, and reshape it in real time, network latency is not a minor inconvenience. It breaks the interaction. A native app running SQLite, DuckDB, or a proprietary binary format directly on disk can scan millions of rows per second without a round trip. No backend, no waiting, no pagination imposed by an HTTP API.

Deep OS integration. File system watchers. Hardware peripherals: serial ports, USB HID devices, barcode scanners, MIDI controllers, proprietary lab instruments. System tray presence. Global keyboard shortcuts. IPC with other local processes. Secure enclave access. These are native primitives. Wrapping them inside a browser adds friction, security restrictions, and maintenance overhead that grows over time. The web platform’s sandboxing is a feature for most software; for this class it is an obstacle.

Regulated or air-gapped environments. Finance, healthcare, defense, industrial control: some data cannot leave the machine. The compliance model for a locally-installed, auditable executable is simpler and more robust than one that sends data to a cloud service, even an encrypted one. “It never leaves the device” is a position that auditors understand.

None of this means “build everything as a native app.” It means: when you are in one of these categories, choosing the web primarily for deployment convenience is a mistake you will reverse later, at greater cost.


Native vs. cross-platform: the real tradeoff

The question is not “native or Electron.” The spectrum is wider than that.

Fully native (Swift/AppKit for macOS, C++/Win32 or WinUI for Windows) gives you the best rendering fidelity, the smallest binary, the lowest memory baseline, and the tightest integration with platform APIs. It also means maintaining separate codebases. For consumer apps where the UI is the product, where pixel-perfect platform conventions matter to every user, this is often worth it. For internal tooling or B2B applications where the audience is homogeneous (a company that standardized on macOS, for example), it is almost always worth it.

Rust with native GUI frameworks (egui, Iced, Slint, or raw wgpu for fully custom rendering) is a strong position for performance-critical or cross-platform work where web technology is not appropriate. Rust gives you memory safety without a garbage collector, which matters for latency-sensitive work: there are no GC pauses, no unpredictable stop-the-world events in the middle of a render or a computation. The ecosystem is younger than Qt or wxWidgets, but the language-level guarantees are genuinely better.

Tauri uses the OS WebView (WebKit on macOS, WebView2 on Windows) for the UI layer, with a Rust backend that handles system access. It is a serious option: much smaller binaries than Electron, much lower memory usage, and full access to Rust’s ecosystem for the parts of the application that require performance. The tradeoff is that your UI rendering is OS-dependent: Safari’s WebKit on macOS may behave differently from Chromium-based WebView2 on Windows. For most business applications, this is manageable.

Electron remains defensible for teams that have significant JavaScript/TypeScript investment and need to ship cross-platform quickly. The V8 JavaScript engine and Chromium renderer are predictable and high-quality. The known weaknesses are real but often acceptable when weighed against development speed and ecosystem access: binary size (often 100MB+ before any application code), memory overhead (two processes minimum: main and renderer), and startup time. The mistake is not choosing Electron; it is choosing Electron without understanding the constraints and designing around them.

Qt with C++ or Python (via PyQt or PySide) is still the right answer for certain categories: complex custom widget rendering, applications targeting embedded Linux, or teams with existing C++ expertise. Qt’s toolchain is mature, its documentation is comprehensive, and its cross-platform rendering model is consistent in a way that WebView-based approaches are not.

The pattern we see in failed desktop projects: technology was chosen without a clear model of who the users are, what the data volumes look like, and which platform features the application actually needs. When those questions are answered first, the technology choice usually becomes less contentious.


Performance for long sessions and large data

A desktop application that starts fast and degrades after four hours is a failure. This pattern is common and almost always has the same root causes.

Memory growth. Either the application holds references it should release (a genuine leak), or it accumulates state that is conceptually correct but grows without bound. The solution is the same: model your application’s data lifecycle explicitly. Know what data lives for the duration of a session, what lives for the duration of a document or workspace, and what lives only for a single operation. Make those lifetimes visible in the code.

Rendering budget. On a 4K display at 60 Hz, you have roughly 16 milliseconds per frame. Any work done on the main thread during a frame contributes to that budget. Database queries, file I/O, and network calls do not belong there. Structure the application so that the render path touches only pre-computed, display-ready data. Move everything else to background threads or async tasks.

Cold query paths. The first time a user queries a large data set, there are no caches warm, no indexes loaded. If that first query takes eight seconds, the user questions whether the application is working. Invest in making cold paths acceptably fast. Show partial results immediately while the full query completes, or pre-warm frequent access patterns in the background.

Process isolation. For applications that ingest untrusted data (parsing documents, processing media files, executing plugins), running the parsing logic in a separate process protects the main process from crashes and limits the blast radius of a security vulnerability. macOS App Sandbox and Windows App Container are worth the adoption cost for consumer-facing applications. For internal tools, even a simple subprocess boundary is better than running untrusted code in-process.


Auto-update and distribution

Distribution is where well-engineered desktop software frequently fails operationally.

Auto-update done wrong produces: silent update failures that leave users on outdated versions; updates that break configuration the user has customized; crashes during update that leave the application in a partially-replaced state.

A solid update architecture has a few non-negotiable properties. The update payload must be cryptographically signed, and the updater must verify the signature before applying anything. The update must be downloaded to a staging location and applied atomically: either it succeeds completely or it does not apply at all, with the previous version intact. The application must start the old version cleanly if the new version fails to launch after update. Update checks should be non-blocking: they happen in the background and prompt the user rather than interrupting their work.

On macOS, Sparkle handles this correctly and has a long maintenance history. On Windows, Squirrel or WiX-based installers with delta patching are well-understood. Tauri ships its own updater that covers both platforms with the same signing and atomic-swap model.

Code signing and notarization are not optional for consumer-facing software. On macOS, an unsigned application triggers Gatekeeper warnings that effectively block adoption. On Windows, unsigned binaries trigger SmartScreen warnings that erode user trust. These processes require annual certificate renewal and integration into the CI/CD pipeline. They are not hard to set up, but easy to neglect until they become urgent.

For enterprise distribution, consider whether your update model needs to work inside a corporate network that blocks direct internet access. Proxy support and on-premises update servers are worth designing for early if your target market includes large organizations.


The long-term maintenance argument

Desktop software lives longer than most software. A web application can be deprecated and the users redirected. A desktop application that users depend on gets used until something forces a change: a macOS major version breaks it, or Windows drops an API, or the signing certificate expires and the updater stops working.

This makes the technology choice a long-term commitment. Choosing a framework that the upstream maintainer may abandon (or that depends on a single company’s continued investment) creates risk that compounds over years. Electron’s backing from OpenJS Foundation and GitHub makes it more durable than a niche framework with a smaller community. Rust’s governance model and the momentum behind projects like Tauri make them credible long-term bets. Qt’s age and commercial backing make it conservative in the best sense.

The engineering work that pays dividends over the long term: clear separation between application logic and the UI framework (so that a UI technology migration doesn’t require rewriting business logic); comprehensive integration tests that run on CI against real OS environments; a signing and notarization pipeline that is automated end to end; and documentation of the decisions made and why, so that the team maintaining the software five years from now understands the constraints they are working within.


What serious desktop work looks like in practice

The projects that succeed share a few characteristics. They start with a precise definition of the user’s workflow and the data it involves. They choose a technology stack based on that workflow, not on what the team already knows or what is currently popular. They invest early in the operational infrastructure: code signing, auto-update, crash reporting, and telemetry. They treat the application as a long-lived product with its own release cadence and upgrade path, not a one-time build.

The projects that fail either chose the wrong abstraction layer for the problem (a browser-based tool for data that never leaves the machine, or a fully native app for a use case that didn’t need it), or they neglected the operational side until it became a crisis.

Desktop software is not a niche. For certain problems it is the correct answer, and building it well requires a specific combination of systems thinking, OS knowledge, and operational discipline. When those conditions are met, the result is software that is faster, more reliable, and more trustworthy than any web alternative, and that earns its place on the user’s machine.


If you are evaluating whether a desktop application is the right approach for a problem you are working on, we are glad to think through it with you.

Bring us the problem you cannot get wrong.

Tell us what you are building. We will tell you how we would approach it, where the real risks are, and whether we are the right team to take it on.

Start a project

© 2025–2026 AYA MIM SRL. All rights reserved.