macOS Electron app publishing distribution process and code signing for desktop applications

Key takeaways

To notarize an Electron app you run one four-step pipeline. Sign with a Developer ID cert, package to .dmg or .pkg, notarize with xcrun notarytool, staple the ticket. Skip a step and macOS refuses to launch the build.

altool is gone. Apple removed altool --notarize-app on 1 November 2023. Every working 2026 pipeline uses notarytool. A build script that still shells out to altool is broken, whether or not your tests noticed.

The 2026 Electron toolchain is scoped and current. Use @electron/osx-sign and @electron/notarize 3.1.x (not the old unscoped packages), Electron Forge 7.11 for new projects, and Hardened Runtime with only the allow-jit entitlement.

Set up once, ship in minutes. The first pipeline (Developer ID, CI, secrets) is a two to three week job. After that a release is one git tag that runs in 12 to 18 minutes, and notarization latency is the only variable.

Electron is a choice, not a default. The July 2026 benchmark puts a Tauri 2 build at 3.2 MB against 85 MB for Electron, and 42 MB idle RAM against 168 MB. Electron still wins on team velocity and identical cross-platform rendering. Pick by constraint.

Why Fora Soft wrote this macOS publishing playbook

We have shipped desktop clients on macOS for more than a decade: Electron, native Swift, and lately Tauri. Along the way we hit most of the traps Apple has shipped. Signing regressions during the arm64 migration. The 2023 removal of altool. Hardened Runtime fighting native Node modules. A notarization queue that stalled during launch week. This playbook is the shortlist of what still works in 2026, written for the engineer who has to make the release green by Friday.

A few references behind the advice. Our desktop clients for VALT, a secure video-surveillance platform used by 770+ US law-enforcement and medical organizations, ship notarized builds every release because operators verify them. BrainCert’s proctoring companion has to pass stapled-notarization checks under aggressive corporate antivirus, so we learned what breaks first. And our software troubleshooting and optimization service regularly inherits desktop projects where a prior team shipped a signed-but-not-notarized app that Apple now blocks. Most of these apps wrap a real-time media pipeline; if you want the layer underneath, our digital-video foundations in Fora Soft Learn covers it.

If you would rather skip to shipping, we build and publish macOS desktop apps end to end, including the CI signing and notarization pipeline most teams put off for months.

Notarization broken on your release branch?

Book 30 minutes with a Fora Soft engineer who has shipped dozens of signed and notarized Electron and native macOS apps. Typical outcome: your CI pipeline goes green within the week.

Book a 30-min call → WhatsApp → Email us →

Why publishing on macOS is harder than it looks

macOS treats an unsigned or unnotarized app as hostile. On every launch a downloaded app passes three checks: Gatekeeper verifies the Developer ID signature, XProtect scans for known malware, and the system looks for a valid notarization ticket. Fail any one and the user gets a red-bordered “cannot be opened” dialog. Since macOS 15 Sequoia there is no Control-click shortcut to wave it through either; the user is routed into System Settings and a multi-click confirmation. That friction is expensive. In our own support engagements, roughly half of first-run attempts on an unnotarized build fail before the app ever opens.

macOS Gatekeeper's three launch checks: Developer ID signature, XProtect scan, and a valid notarization ticket

Figure 1. The three checks macOS runs before an app opens. Miss the signature or the stapled notarization ticket and the launch is blocked.

The historical pain is that Apple has rewritten its notarization tooling. The first generation used xcrun altool --notarize-app with an Apple ID and an app-specific password. Apple deprecated that in Xcode 13 and removed it on 1 November 2023. The replacement is xcrun notarytool, with different flags, better auth options, and much faster turnaround: 2 to 15 minutes instead of the old 20 to 60. Any guide older than 2024 is describing a pipeline that no longer exists.

The second pain is coverage. Every binary in the bundle has to be signed with the Hardened Runtime: native Node modules, Electron Framework helpers, Squirrel update helpers, bundled CLIs. One unsigned dylib buried in node_modules/ fails the whole notarization with a cryptic log. Electron Forge and electron-builder hide most of this, but when they fail you have to understand the layer underneath.

The four-step macOS publishing pipeline in 2026

At the Unix level every macOS publishing pipeline does the same four things in the same order. Understand these and the tool choice becomes a detail.

The four-step macOS publishing pipeline: sign, package, notarize with xcrun notarytool, then staple the ticket

Figure 2. The pipeline every distribution path shares. Notarize is step 3, and it is where most broken builds actually fail.

StepWhat it doesCommandTypical time
1. Code signProve authorship with a Developer ID certcodesign --options runtime10–60 s
2. PackageWrap the .app in a .dmg, .zip or .pkgelectron-builder --mac dmg30 s–3 min
3. NotarizeUpload to Apple’s Notary service for a malware scanxcrun notarytool submit --wait2–15 min
4. StapleEmbed the ticket so offline launches workxcrun stapler staple1–5 s

Miss step 3 and the user sees “this app is damaged and can’t be opened.” Miss step 4 and the app works only when the user has network at first launch, because Gatekeeper cannot reach Apple to fetch the ticket. Both are real bugs we have pulled out of production.

Reach for the full four-step pipeline when: you distribute outside the Mac App Store, whether that is a direct .dmg, a Homebrew Cask, enterprise MDM, or an auto-updater. The Mac App Store path is separate and has its own section below.

Step 1 — Code signing with a Developer ID certificate

Every macOS app distributed outside the Mac App Store needs a Developer ID Application certificate. That means a $99/year Apple Developer Program membership and about 30 minutes of setup. Two cert types matter here.

Developer ID Application signs the .app bundle and is required for notarization. It identifies your organization and Apple can revoke it for abuse. Developer ID Installer signs .pkg installers and is separate; you only need it if you ship a package installer instead of a drag-to-Applications .dmg.

Hardened Runtime is mandatory

The Notary service rejects any app not signed with the Hardened Runtime flag (--options runtime). Hardened Runtime blocks code injection, library swaps, and some debugger attachments. An Electron app needs exactly one entitlement exception, com.apple.security.cs.allow-jit, because V8 compiles JavaScript to native code at runtime. Anything looser, especially allow-unsigned-executable-memory, either fails notarization or trips security review on the Mac App Store.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>com.apple.security.cs.allow-jit</key>
  <true/>
</dict>
</plist>

Save that as build/entitlements.mac.plist and reference it from electron-builder.yml or forge.config.js. Add another entitlement only when a specific feature demands it, such as microphone, camera, or a local network server. Each extra entitlement is one more attack surface and one more App Review question.

Step 2 — Packaging as .dmg, .zip, or .pkg

macOS accepts three package types, each with a different trade-off.

.dmg (Disk Image). The Mac-native drag-to-Applications experience, and the right default for a consumer app. It supports a custom background, a license screen, and an install flow that feels native. Electron Forge, electron-builder, and native Xcode builds all produce DMGs.

.zip. The pick for auto-update payloads (Sparkle, or electron-updater with Squirrel.Mac). Smaller than a DMG, faster to extract, no mount step. The updater unzips and swaps the bundle, so users never see it.

.pkg (Installer Package). Best for enterprise MDM and apps that install a helper daemon, a LaunchAgent, or a system extension. Slightly more friction for a consumer download, but the only sane choice when the app needs admin privileges at install time. It needs the separate Developer ID Installer cert.

Reach for .dmg when you ship a consumer or prosumer app as a direct download; reach for .pkg when the app installs daemons or system extensions; reach for .zip only as an auto-update payload, never as the first install.

Step 3 — Notarizing with xcrun notarytool

Notarization is Apple’s automated malware scan. You upload a signed package, Apple scans it on their servers, and you get back either “accepted” with a ticket you can staple, or a rejection log that names what broke. The 2026 tool is xcrun notarytool, shipped with the Xcode Command Line Tools (Xcode 14 and up; Xcode 26 today).

Three authentication options, picked by context

1. App-specific password (simplest). Generate one at appleid.apple.com and pass it with --password. Fine for local dev and a small team. The catch is rotation: every team change means a new password.

2. App Store Connect API key (best for CI). Download a .p8 key and pass --key --key-id --issuer. No per-user password, rotatable centrally, and it survives team turnover. This is what we run on Fora Soft CI. On Xcode 26 you can also use an individual API key and omit the issuer.

3. Keychain profile (safest for local). Run notarytool store-credentials once, keep the profile in the Keychain, then pass --keychain-profile. The secret never touches an env var or a build log.

End-to-end commands

# 1. Sign the .app bundle (Hardened Runtime + entitlements)
codesign --deep --force --verify --verbose \
  --options runtime \
  --entitlements build/entitlements.mac.plist \
  --sign "Developer ID Application: Acme Inc (XXXXXXXXXX)" \
  dist/Acme.app

# 2. Package into a .dmg (electron-builder does this for you)
electron-builder --mac dmg

# 3. Submit for notarization and block until the result is back
xcrun notarytool submit dist/Acme-1.0.0.dmg \
  --apple-id   "$APPLE_ID" \
  --team-id    "$APPLE_TEAM_ID" \
  --password   "$APPLE_APP_PASSWORD" \
  --wait

# 4. Staple the ticket so the app launches offline too
xcrun stapler staple dist/Acme-1.0.0.dmg

# 5. Verify the whole thing with Gatekeeper
spctl -a -vvv --type install dist/Acme-1.0.0.dmg

Electron teams usually wire this into the afterSign hook in electron-builder.yml using @electron/notarize, the scoped replacement for the deprecated electron-notarize. On Electron Forge 7, the maker-dmg plus the osxNotarize config wires the pipeline in about 20 lines.

Need the notarization CI pipeline built once, properly?

Fora Soft runs a one-week Mac publishing sprint: Developer ID and App Store Connect keys, a GitHub Actions workflow, signing plus notarization plus stapling, tested on Sonoma, Sequoia and Tahoe 26. You get the runbook and a secrets-rotation plan.

Book a 30-min scoping call → WhatsApp → Email us →

Step 4 — Staple, then verify, then ship

Stapling embeds the notarization ticket into the artifact so Gatekeeper can check it offline. Skip it and Gatekeeper has to fetch the ticket from Apple on first launch, which breaks air-gapped installs, corporate networks that block Apple’s host, and the first 30 seconds after a conference Wi-Fi sign-in. Always staple.

After stapling, run spctl -a -vvv against the artifact. A good build reports “source=Notarized Developer ID” with the cert identity. Anything else, such as “source=Unnotarized Developer ID,” a rejection, or a CSSM error, means something is still wrong. Capture this in CI so the build fails closed if the pipeline regresses. Apple’s notarization reference documents each rejection code.

The Electron toolchain in 2026 — what to pick

Electron’s publishing ecosystem has settled on a few canonical packages. The old unscoped modules (electron-notarize, electron-osx-sign) are deprecated in favor of their scoped successors (@electron/notarize, @electron/osx-sign). If your package.json still names the old ones, upgrade.

PackageWhat it doesStatusRecommend for
Electron Forge 7.11Unified build / package / publish CLIOfficial, currentNew projects
electron-builderBuild + multi-target packagingCommunity, matureExisting projects, complex targets
@electron/osx-signSign .app bundlesOfficial, currentAny signing workflow
@electron/notarize 3.1Wrap notarytoolOfficial, currentAny notarization workflow
electron-updaterAuto-update via Squirrel.MacCommunity, currentMost Electron apps
electron-notarize (unscoped)Old notarization wrapperDeprecatedDelete from package.json

Our default for a new Electron project: Electron Forge 7.11 with the DMG and ZIP makers, @electron/notarize via the osxNotarize hook, a universal arm64 plus x64 build from the macUniversal maker, and GitHub Actions with App Store Connect keys in repo secrets. Stable Electron sits at v42 as of mid-2026, on a roughly 12-week major cadence, so pin a version and schedule the upgrade. Total setup is about a day for a senior, two to three for someone new to the stack.

Alternatives to Electron — when not to use it

Electron is the right pick for most desktop apps in 2026: cross-platform reach, a deep ecosystem, fast onboarding for a JavaScript team. It is not the only pick, and for some products the alternatives win by a wide margin. The July 2026 numbers make the trade concrete.

Electron vs Tauri 2 vs native Swift on bundle size, idle memory and cold start (Jul 2026 benchmark); Tauri is smallest

Figure 3. The runtime tax, measured. An independent July 2026 benchmark put Tauri 2 well ahead on size, memory and cold start; Swift is the native reference.

Tauri 2. A Rust backend with the system WebView on the front. The July 2026 benchmark measured a Hello-World bundle at 3.2 MB against 85 MB for Electron 34.x, idle memory at 42 MB against 168 MB, and a cold start of 380 ms against 1,420 ms. The cost is a smaller ecosystem, fewer off-the-shelf Node packages, and a Rust learning curve on the backend. Strong when bundle size, memory, or high-volume deployment is the story. It reached production maturity with the 2.0 release in late 2024.

Native Swift and SwiftUI. macOS only, but uncompromising on platform polish, performance, and native API access. It fits an app that is 80%+ Mac users, integrates deeply with Finder, Spotlight, or system services, or targets a prosumer audience that pays for native. Our Swift 6 features guide and MVVM-C architecture playbook carry over mostly intact, and our Apple performance guide applies the same way.

.NET MAUI and Avalonia. The pick when the team already lives in C#. Avalonia produces small cross-platform binaries with a native feel and has been production-ready since 2023. A smaller community than Electron, but credible for line-of-business apps.

Reach for Tauri when a 3 MB download or a 40 MB memory floor is a selling point and the team can carry Rust; reach for native Swift when Mac is the audience and deep OS integration is the product; stay on Electron when velocity and identical cross-platform rendering matter more than bundle size.

Auto-updates — Sparkle, Squirrel.Mac, and staged rollout

A desktop app needs an update story. Without one, every fix asks the user to re-download and reinstall, a large share never will, and within a year your install base runs five different vulnerable versions. Treat updates as a product surface. Our Electron desktop app guide goes deeper on the business side of this.

Sparkle is the 20-year-old native option, used by 1Password, Sketch, and Things. Background download, silent install, EdDSA (ed25519) signature verification, staged rollout, release notes. Since 2026 it requires EdDSA (DSA-only is retired). Excellent for native Swift, usable from Electron through a shim.

electron-updater (Squirrel.Mac) is the Electron default. It works against GitHub Releases, S3, or a generic HTTPS feed, ships delta updates to keep bandwidth small, and drops into electron-builder or Forge in a few lines.

Staged rollout. Never ship to 100% of your base on day one. Start at 10% for 24 hours, 50% for 48, then 100%, and wire crash telemetry (Sentry, Crashlytics) to the rollout so a regression auto-pauses the next stage. This is the single biggest post-launch risk reduction a desktop app can buy.

Reach for Sparkle when you ship native Swift and want EdDSA-signed background updates with staged rollout built in; reach for electron-updater when you are on Electron and already publish to GitHub Releases, S3, or a generic HTTPS feed.

Five notarization errors you will hit — and how to fix them

1. “The binary is not signed with a valid Developer ID certificate.” A native module, helper binary, or framework in the bundle went unsigned. Run codesign --deep or, better, let @electron/osx-sign auto-discover nested binaries. Native Node modules with postinstall scripts are the usual culprit.

2. “The executable does not have the hardened runtime enabled.” A nested binary is missing --options runtime, usually a helper CLI you bundled. Re-sign it with the flag.

3. “The signature of the binary is invalid.” You changed the bundle after signing, maybe a config file or a post-build script. Re-sign after every modification; one extra byte invalidates the signature.

4. “com.apple.security.cs.allow-unsigned-executable-memory is not allowed.” An old Electron dev entitlement leaked into production. Remove it; modern Electron runs on allow-jit alone.

5. “status: Invalid” with an empty log URL. Usually a corrupt upload. Retry once. If it sticks, the artifact is probably not a valid bundle, for example an unsigned .app zipped up. Sign first, zip second.

Distribution channel comparison

Where you ship changes the economics as much as how you build. Answer the audience question first, then read the table.

macOS distribution decision tree: Mac App Store, MDM .pkg, Homebrew, Setapp, or default Developer ID direct .dmg

Figure 4. Pick a distribution channel top-down. The first Yes wins; the default is Developer ID plus a direct .dmg, where you keep 100%.

ChannelYou keepDiscoveryReviewBest fit
Developer ID + direct DMG100%Your marketingNone (notarization only)B2B, prosumer, power users
Mac App Store70%, or 85% via SBPBuilt-in24–48h App ReviewConsumer, impulse-buy apps
Homebrew Cask100%Dev communityCommunity PRDeveloper tools
Enterprise MDM (.pkg)100%B2B salesNoneEnterprise, regulated industries
SetappRevenue shareSubscription catalogSetapp approvalProsumer, recurring-use tools

On the Mac App Store, Apple takes 30%, dropping to 15% through the App Store Small Business Program if your proceeds are under $1M a year, or after a subscriber’s first paid year. Most B2B apps ship Developer ID plus direct download first, add the App Store once the product is stable, and skip Setapp unless a subscription bundle fits. Consumer apps often invert that: App Store first for discovery, direct download as a paid pro tier. Pick by where your audience already looks for apps.

Wiring the pipeline into GitHub Actions

Here is the minimal macOS publish workflow we run on internal projects. It uses a macos-15 runner, imports the signing identity from a base64 .p12, and calls Electron Forge’s publish target, which handles signing and notarization internally.

name: release-macos
on: { push: { tags: ['v*'] } }

jobs:
  release:
    runs-on: macos-15
    env:
      APPLE_ID:           ${{ secrets.APPLE_ID }}
      APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
      APPLE_TEAM_ID:      ${{ secrets.APPLE_TEAM_ID }}
      CSC_LINK:           ${{ secrets.MAC_CERTS }}
      CSC_KEY_PASSWORD:   ${{ secrets.MAC_CERTS_PASSWORD }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm ci
      - run: npm run make -- --arch=universal
      - run: npm run publish

End to end on a macos-15 runner, a 120 MB Electron app takes 12 to 18 minutes: 4 to 6 to build, 1 to 2 to sign, 5 to 10 to notarize, and a few seconds to staple and publish. GitHub bills macOS at $0.062 a minute in 2026, a 10x multiplier over Linux, so a release costs roughly $0.75 to $1.15 in runner minutes. Teams shipping many releases a day pay back a dedicated Mac (a Mac mini or Mac Studio on a runner service) quickly.

Mini case — rescuing a stuck macOS release

Situation. A client running a streaming SaaS had an Electron desktop companion with a dead release pipeline: every build failed notarization after Apple pulled altool. The team had shipped unnotarized updates for three months and lost install data from users who could not launch the app. Their last good release was on macOS Ventura; newer users on Sonoma hit the “cannot be opened” dialog.

One-week sprint. Day 1, audit: the pipeline used electron-notarize 1.x calling altool. Days 2 to 3, upgrade to @electron/notarize 3.x on App Store Connect API-key auth. Day 4, replace the entitlements file (it still carried allow-unsigned-executable-memory) with an allow-jit-only plist. Day 5, wire GitHub Actions and test across a Sonoma, Sequoia, and Tahoe 26 matrix. Day 6, ship a canary to 10% and watch Sentry. Day 7, full rollout.

Outcome. The pipeline now runs in 14 minutes per release. That client’s install-to-first-run conversion recovered from 54% to 91% inside two weeks. Releases go out weekly on a one-click git tag, and the team kept the runbook for future rotations. Want a similar release-pipeline rescue?

Release pipeline stuck on deprecated tooling?

Fora Soft runs one-week macOS-pipeline rescues with a senior Node and macOS engineer plus Agent Engineering support. Typical cost lands 30 to 40% below an equivalent agency scope, because the agents do the log triage and entitlement audits.

Book a 30-min pipeline audit → WhatsApp → Email us →

A decision framework — macOS publishing in five questions

Q1. Is your audience B2B, enterprise, or power users? Ship Developer ID plus a direct DMG first. The Mac App Store is a distraction until the product is stable.

Q2. Do you need Windows or Linux reach too? Yes points to Electron or Tauri. No frees you to go Swift or SwiftUI, with the performance and polish that brings.

Q3. Is bundle size a real constraint? Electron starts around 80 to 200 MB; Tauri lands at 2 to 10 MB. For slow-network distribution, MDM size caps, or a story that leans on “fast,” Tauri wins the trade.

Q4. Is the team already deep in JavaScript or TypeScript? Yes points to Electron Forge 7 with the TypeScript template. The team ships faster and maintenance stays linear with headcount.

Q5. Do you need auto-updates? Assume yes; every desktop app does. Wire electron-updater or Sparkle on day one, staged rollout on day two, telemetry on day three.

Five macOS publishing pitfalls to avoid

1. Deprecated tooling. altool, the unscoped electron-notarize and electron-osx-sign, and any guide written before 2024. Audit your package.json and build scripts before you trust them.

2. Over-permissive entitlements. Every extra entitlement is an attack surface and an App Review question. Start with allow-jit only and add others with a written justification.

3. Skipping stapling. Stapler is effectively free. Skip it and you break air-gapped installs and corporate networks that block Apple’s Gatekeeper endpoint. Always staple.

4. No staged rollout. A 100% day-one rollout turns one bug into an outage. Wire a 10, 50, 100 percent rollout with an automatic pause on crash-rate regression. Our crash-proof software playbook covers the wider pattern.

5. Credentials in the repo. App-specific passwords and .p12 certs committed to git are the most common root cause of desktop credential breaches we see. Use Actions secrets or App Store Connect keys, and rotate quarterly.

KPIs — what to measure on a macOS desktop app

Publishing KPIs. Notarization time P50 (under 10 minutes), release-pipeline time (under 20 minutes end to end), release frequency (weekly or better), and broken-build escape rate (under 2% of releases). These tell you whether the pipeline is healthy.

Install KPIs. Install-to-first-run conversion (over 90%), first-day retention by macOS version, and update adoption (share of the base on the latest version within 7 days, over 70%). These tell you whether the app is actually launching.

Quality KPIs. Crash-free sessions (over 99.5%), hang rate (under 0.5%), steady-state memory, and idle CPU. Same quality bar as mobile, same thresholds. Our testing-at-every-stage guide covers baking these into CI.

When NOT to build a macOS desktop app at all

Sometimes the right macOS app is no macOS app. Three cases where the usual advice is wrong.

1. A SaaS with no offline use case. A Progressive Web App in Safari gives you installability, offline caching, and notifications with zero notarization overhead. Unless you need the filesystem, hardware, or the system tray, the PWA wins.

2. Mac is under 10% of your users. A macOS client costs roughly 30 to 40% of the web client per year to build and maintain. Do not pay that without the users to justify it. Our cross-platform framework guide walks the build-vs-skip math.

3. You ship features weekly. Desktop auto-update latency runs 2 to 7 days from release to majority adoption. If your product iterates faster than that, users live on stale builds. Web, or a hybrid PWA, fits that tempo better.

FAQ

Is xcrun altool still usable for notarization in 2026?

No. Apple removed altool --notarize-app on 1 November 2023. The only supported command-line tool for notarization in 2026 is xcrun notarytool, shipped with Xcode 14+ and the current Command Line Tools. A build script that still references altool is broken.

Do I need an Apple Developer Program membership to publish a macOS app?

Yes, if you want the app to launch without warnings on any recent macOS. The $99/year membership gives you the Developer ID certificate to sign with and access to the Notary service. Without it, users hit “app is damaged” or “unidentified developer” errors, and about half of first-run attempts fail.

How long does notarization actually take?

P50 on notarytool is 2 to 10 minutes for a 100 to 200 MB Electron bundle, with P95 around 15. Apple-side delays during major OS releases (June betas, September releases) can push it to 30 to 60 minutes, but those are rare. Always pass --wait so CI blocks until the result is back.

Electron Forge or electron-builder — which should I pick?

For a new project in 2026, Electron Forge 7.11 is the official default and the lowest-friction path; it bundles signing, notarization, universal binaries, and update publishers in one CLI. electron-builder is still excellent for existing projects or complex multi-target builds (Windows Store, Snap, Flatpak plus macOS). Do not mix both.

Should I build a universal binary (arm64 + x86_64)?

Almost always yes in 2026. Apple Silicon is the majority of shipping Macs and Intel machines are still supported. A universal binary is about 40% larger than a single-arch build but gives you one artifact for everyone. Use the macUniversal maker in Forge or arch: universal in electron-builder.

Is Tauri production-ready?

Tauri 2, released late 2024, is production-ready for apps that can live with a Rust backend and the system WebView (WKWebView on macOS). 1Password, Cloudflare, and others ship Tauri in production. The trade is a smaller ecosystem than Electron and a Rust learning curve. When bundle size, memory, or startup time is the story, it is a strong pick.

How do I handle auto-updates securely?

Three rules. Serve updates over HTTPS. Verify each download’s signature against a pinned key (Sparkle has EdDSA built in; electron-updater checks the Developer ID signature). Stage the rollout 10, 50, 100 percent with crash telemetry pausing the next stage on a regression. Skip any one and a bad release becomes an outage.

What is the difference between Mac App Store and Developer ID distribution?

Mac App Store distribution needs the App Store cert, sandboxing, and App Review (24 to 48 hours). You pay 15 to 30% but get discovery and built-in purchases. Developer ID is direct download: you keep 100% and ship as fast as you can notarize, but discovery is on you. Most B2B apps start Developer ID; consumer apps often start App Store.

Desktop

Electron desktop apps for business in 2026

When Electron is the right call, what it costs, and how to staff it.

Reliability

How to build crash-proof software in 2026

SLOs, circuit breakers, DORA metrics, feature flags — staying above 99.5% crash-free.

Native macOS

Swift 6 features for native Mac apps

Strict concurrency, typed throws, embedded Swift — the case for going native.

Architecture

The 2026 Apple MVVM-C playbook

Coordinators, DI, Swift 6 concurrency — architecture that survives production.

Quality

What to do if there are too many bugs

Root causes, QA, automated review — when bug load is the symptom, not the problem.

Ready to ship a macOS desktop app properly?

Publishing on macOS in 2026 is one four-step pipeline: sign, package, notarize with xcrun notarytool, staple the ticket. Skip a step and Gatekeeper refuses to launch the app. Lean on deprecated tooling and CI quietly starts shipping broken builds. The Electron toolchain has settled on Electron Forge 7, @electron/osx-sign, and @electron/notarize; the alternatives, Tauri and native Swift, earn their place on bundle size, memory, and platform polish.

Set the pipeline up once and every release afterward is a one-click git tag that ships in about 15 minutes. The cost is a couple of focused weeks. The payback is every week after that. If you want a partner who has done this for a decade across video, e-learning, surveillance, and SaaS, that is the shape of what Fora Soft does, and Agent Engineering now compresses the setup by another 30 to 40% against a traditional shop.

Let’s ship your macOS desktop app.

A 30-minute call with a Fora Soft engineer who has done this dozens of times. You leave with a concrete migration path, a pipeline blueprint, and an honest estimate, whether or not we end up working together.

Book a 30-min call → WhatsApp → Email us →

  • Development