Composition
Desktop apps
Ship the same app to macOS, Windows and Linux with the desktop target.Every composition is a website. The desktop target wraps that website in
macOS, Windows and Linux apps built with Electron:
It combines with the mobile target: --targets mobile,desktop.
The desktop app is a window onto the deployed site, not a second build of it.
It loads --url, so:
Last updated October 17, 2026- pages, auth and API routes run on the server exactly as they do in a browser, with the same cookies and the same code;
- every deploy reaches the app at once, with no new installer;
- only desktop/ is packaged (a few kilobytes on top of Electron), and its offline.html is shown when the site cannot load.
- desktop/main.mjs, the main process: one window, links to other sites open in the system browser, a second launch focuses the running app.
- desktop/offline.html, the offline page, and desktop/package.json, the packaged app's own manifest.
- electron-builder.yml with the bundle id, the app name and the installer formats: a DMG on macOS, an NSIS installer on Windows, an AppImage on Linux.
- src/lib/desktop.ts: isDesktopApp(), for the few things that should differ inside the app (hiding a "download the app" link). It reads the user agent, so it also works on the server with the request's user-agent header.
- electron and electron-builder, plus desktop and desktop:build scripts.
- Links to other sites open in the system browser. That includes OAuth providers and Stripe Checkout. Email and password auth stays in the app, because it runs on the site's own routes.
- Signing. Unsigned apps work, but macOS Gatekeeper and Windows SmartScreen warn on first launch. Signing and notarization are set in electron-builder.yml; see electron-builder's code signing guide.
- Updates. The site updates itself, so the installer only changes when Electron or desktop/ does. There is no update feed to run.
Edit this page on GitHub