To ship a desktop app as a side project, you usually do not need a native Mac or Windows rewrite. Pick Electron if you want your web stack inside a Chromium shell, or Tauri if you want a smaller binary that uses the system webview plus a Rust core; ship one OS first; get codesigning, notarization and auto-update right before you chase polish.
This guide is for employed builders with nights and weekends, often people who already have a web app or a local script and keep hearing "is there a desktop app?" Framework facts were checked against Electron, Tauri, Apple and Microsoft primary docs on 5 November 2026. The worked example is made up on purpose.
When does a desktop app beat a website, a PWA or a phone app?
A desktop app is the right shape when the job lives on the computer itself: always-on tray or menu bar access, local files, offline-first tooling, OS shortcuts, or distribution that does not need a store listing on day one. If install-from-the-browser is enough, read turning a side project into an installable web app. If the job is truly a phone job, read shipping your first mobile app as a side project. This post does not re-teach manifests, service workers, App Store accounts or TestFlight.
Job | Desktop app fit | Usually better as |
|---|---|---|
Always-on tray / menu bar companion | Strong | - |
Reads and writes local project folders | Strong | - |
Offline-first tooling with OS shortcuts | Strong | - |
Same UI as your website, no local privileges | Weak | Website or PWA |
Camera, maps, on-the-go capture | Weak | Phone app |
You need store discovery more than a download page | Mixed | Store later, direct download first |
Electron vs Tauri: how do you choose?
Electron embeds Chromium and Node.js so one JavaScript codebase can ship on macOS, Windows and Linux. Tauri lets any HTML/JS/CSS frontend talk to a Rust (or plugin) core and uses the system webview instead of bundling a browser engine. Tauri's docs say a minimal app can be less than 600KB; Electron installers are larger because they ship Chromium and Node with your code. Native Swift, Kotlin or C# apps still win for deep platform UI, but they are a rewrite, not a side-project wrap of what you already built.
Question | Electron | Tauri | Native |
|---|---|---|---|
Language / stack | JavaScript/TypeScript + Node in a Chromium shell | Web frontend + Rust core (Swift/Kotlin plugins optional) | Platform UI toolkits |
Bundle size order of magnitude | Ships Chromium + Node with the app | System webview; minimal app can be under 600KB | Varies by toolkit |
Security model |
| Capabilities / permissions gate what the webview can invoke | OS process model |
Auto-update |
| Official updater plugin with signed feeds | Store or custom |
macOS / Windows / Linux | All three are first-class | All three desktop targets; mobile exists separately | Per platform |
Rule of thumb for a React or Next side project: stay on Electron if you want one rendering target and the npm ecosystem. Pick Tauri when download size and a smaller attack surface matter more than Chromium parity, and you are willing to own a little Rust plus webview differences across OSes.

Why ship one OS first?
For a nights-and-weekends project, pick Mac or Windows first based on where your early users already work. Packaging, codesigning, notarization or SmartScreen, and auto-update each have OS-specific steps. Linux can wait until one paid OS path is boring and documented in your own notes. Cross-compiling Windows NSIS from Linux or macOS is documented for Tauri, but local VMs or CI runners on the target OS are less fragile for a first release.
What does a minimum project look like?
Both stacks start from a scaffold. Electron's packaging tutorial points to Electron Forge: import an existing app with npx create-electron-app@latest import (or scaffold fresh), then use electron-forge start, electron-forge package and electron-forge make, with makers listed in forge.config.js. Tauri starts with npm create tauri-app@latest, then a web frontend folder plus src-tauri for Rust, tauri.conf.json and a capabilities directory (see Tauri's project structure).
Primary path in this post (Electron): one main process file, one preload that exposes a tiny API through contextBridge, one renderer (your existing React UI), and Forge makers for the OS you chose first. Sketch the Tauri twin lightly: frontend build output pointed at by tauri.conf.json, a few invoke commands, and a default capability JSON that lists only the permissions those commands need.
Electron: main + preload + renderer; never put secrets in the renderer.
Tauri: frontend +
src-tauri; grant capabilities per window, not "allow everything".Either way: one OS make/build script that produces an installer you can install on a clean machine.
How do you package installers?
Electron core does not ship packaging. Forge is the officially documented all-in-one pipeline (package then make) and can produce OS-specific distributables such as DMG, MSI and zip through makers. electron-builder is the widely used community alternative; its homepage documents installers plus built-in electron-updater with staged rollouts. Tauri uses tauri build / tauri bundle (see the distribute guide) and can emit DMG or .app on macOS, MSI and NSIS (-setup.exe) on Windows per the Windows installer docs, and AppImage (plus deb/rpm and others) on Linux.
macOS: DMG or
.apparchive for direct download; App Store is a separate track.Windows: MSI (WiX Toolset v3) or NSIS setup exe.
Linux: AppImage is the common "download and run" shape for side projects; add distro packages later if users ask.
What do codesigning and notarization actually mean?
Codesigning attaches your developer identity to the binary so the OS can check it was not altered. On macOS, Apple's Gatekeeper guide explains that software from outside the Mac App Store is checked for a Developer ID signature, and that macOS Catalina and later also expect notarization so Apple can look for known malware. Developer ID certificates come with Apple Developer Program membership. Apple's enrollment help states the Program annual fee is 99 USD per membership year (local currency where available). You create a Developer ID Application certificate for apps shipped outside the Mac App Store, submit the build for notarization, then staple the ticket so offline Gatekeeper checks still pass. Ad-hoc or unpaid Personal Team signing is fine for your own Mac; Apple's membership overview and Tauri's macOS signing guide both note that free accounts cannot notarize, so other people still see unverified warnings.
On Windows, Authenticode signing with SignTool (Windows SDK) or a cloud flow such as Azure Artifact Signing (formerly discussed as Trusted Signing) marks the installer as coming from a publisher. Microsoft Defender SmartScreen still warns on files that are not on its list of well-known, frequently downloaded files, so a brand-new signed build can show caution until reputation builds. Tauri's Windows signing guide notes that signing every release with the same certificate helps reputation carry forward, and that Windows 11 Smart App Control can block unknown unsigned apps entirely when it is on.

How do you ship auto-updates without breaking users?
Do not ask people to re-download the installer every week. Electron's updating applications guide covers the built-in autoUpdater module (Squirrel.Mac / Squirrel.Windows), the free update.electronjs.org service for public GitHub Releases (macOS/Windows, codesigned on macOS), and helpers like update-electron-app. electron-builder's electron-updater adds providers such as GitHub Releases and S3, differential updates and staged rollouts. Tauri's updater plugin requires signed update artifacts (public key in config, private key only in CI), HTTPS endpoints in production, and a static JSON or dynamic server feed. Ship a signed update channel before you grow past a handful of testers. Staged rollout, in one line: send the new build to a percentage of installs first so a bad update cannot brick everyone at once.
Which security basics do first-timers miss?
Electron's security tutorial is blunt: Electron is not a browser. Defaults since recent majors keep nodeIntegration off, contextIsolation on and renderer sandboxing on; leave them that way. Load local packaged UI, not remote HTML with Node powers. Do not disable webSecurity. Prefer a Content-Security-Policy. Validate IPC senders. Never ship API keys or signing private keys inside the binary.
Tauri's security overview and capabilities docs describe a hard split: Rust core code has full system power; the webview only gets what you grant through capabilities and command scopes.
Electron:
contextIsolation: true,nodeIntegration: false, sandbox on; expose only narrowcontextBridgeAPIs.Tauri: start from least-privilege capabilities; do not grant filesystem or shell permissions "just in case".
Both: treat update feeds and download URLs as security boundaries; only install signed updates.
Should you start outside the stores?
Yes for a side project. GitHub Releases plus a simple download page lets you iterate without review queues. Mac App Store and Microsoft Store add discovery and some trust signals, but also agreements, sandbox rules and slower loops. Ship direct download with proper codesigning first; revisit stores when users ask or when enterprise IT requires a store link. If you later open-source the wrapper, keep license choice to one honest line and point at open-sourcing a side project without regretting it.
How do you measure installs lightly?
Count GitHub Release asset downloads for a coarse install signal. Optionally add a first-run ping that only fires after an in-app consent screen, and keep it to one event with an app version string. For product analytics on the marketing site or account dashboard, reuse what you already check on Mondays; see analytics for a side project you will actually check. This section is not an analytics tooling guide.
Weak patterns vs better patterns
Weak | Better |
|---|---|
Unsigned DMG / EXE and a blog post saying "ignore the warning" | Developer ID + notarization (Mac) or Authenticode (Windows) |
Giant Electron build with | Isolated preload API, Node off in the renderer |
"Please download the new zip" every release | Signed auto-update feed with a staged rollout |
Shipping Mac and Windows and Linux in week one | One OS until signing and updates are boring |
Hard-coding secrets into the packaged app | Secrets only on your server or in the user's keychain |
Which traps catch first-time desktop shippers?
Polishing UI for three weekends before the first signed installer exists.
Testing only on your already-trusted machine (Gatekeeper and SmartScreen behave differently for strangers).
Turning off Electron isolation flags "just to make IPC easier".
Losing the Tauri updater private key or the Apple/Windows signing cert backup.
Promising Linux, Mac App Store and Microsoft Store on the launch tweet.
A made-up example: Mira and Querntray
Mira is a backend engineer. Querntray is invented for this article: a menu-bar / tray clipboard helper that keeps colour codes and asset URLs for a small design team. Numbers below are made up.
She already had a React UI for a private web version. Users asked for a desktop app so pastes worked offline during flights. She chose Electron because the UI was already React and she did not want a Rust learning week before the first install. Weekend one: Forge import, tray window, one OS (Mac, because her five testers were on Mac), Developer ID signing and notarization wired in CI with environment variables, not files committed to git. Weekend two: update-electron-app pointed at GitHub Releases, a first-run consent ping, and a Windows NSIS build only after two Mac releases felt calm. She skipped stores. Download counts on GitHub plus three customer replies were enough signal to decide the next feature.
A one-weekend / two-weekend plan
Timings are suggestions for an employed builder, not promises.
Block | Focus | Done when |
|---|---|---|
Friday evening | Fit check + stack pick (Electron or Tauri) + one OS | Written decision in the README |
Saturday morning | Scaffold, load your existing UI, tray or main window | App runs locally on your machine |
Saturday afternoon | Package an installer; install on a clean profile/VM | You can open the installed app without the dev command |
Sunday | Codesign (+ notarize on Mac); publish to GitHub Releases | A friend can install without you screensharing |
Next weekend | Auto-update + minimal first-run metric + second OS only if needed | An update installs from the feed on a test machine |
FAQ
Electron or Tauri for a React or Next side project?
Electron if you want Chromium parity and the least new language surface. Tauri if a small download and capability-based IPC matter more, and you accept system webview differences plus some Rust.
Do I need an Apple Developer account?
To distribute a Mac build other people can open without scary Gatekeeper detours, yes: a paid Apple Developer Program membership is what Apple documents for Developer ID signing and Mac software notarization. A free Personal Team is for your own devices and expires quickly.
Can I wrap my existing website?
You can load local UI that talks to your API. Loading a remote site with Node integration enabled is exactly what Electron's security guide warns against. Prefer a packaged renderer and a small trusted bridge.
Will antivirus or SmartScreen flag my app?
New downloads often get caution screens until reputation exists. Signing helps identity; it does not skip reputation. Unsigned builds are worse, and Smart App Control can block them outright.
Ship the installer people can trust
Pick the shell that matches your stack, finish one OS with signing and updates, then invite real users. When you want a calm place to launch the side project around that desktop build, SideHunt is built for weekly side-project hunts.