GenerateSaaS

Configuration

How the --desktop flag maps to the generated config.desktop block, its fields, and the per-environment backend URL.

Configuration (config.desktop)

When scaffolded with --desktop, @repo/config emits a config.desktop block (typed by DesktopConfig), derived from your app name and base URL at init. Examples below assume an app named Acme on acme.com.

FieldExampleDescription
enabledtrueWhether the desktop app ships with this project.
appIdcom.acme.acmeReverse-DNS application id - the installer id plus the Windows AppUserModelID. The domain part is the base-URL domain reversed (acme.com -> com.acme); the last segment is a slug of the app name.
productNameAcmeDisplay name for the window title and installer (your app name).
protocolacmeCustom deep-link URL scheme without ://, a slug of the app name.
baseUrlhttps://acme.comWeb app origin the desktop targets in production builds - the default backend API origin (backend-url.ts pins every bridged request to it) when no BASE_URL/PUBLIC_API_URL env is set.
dataFolderdataFolder name for the app's persisted files (logs, AI-agent data, generated artifacts), created under the OS app-data dir. Rename at will.
autoUpdate.urlhttps://cdn.acme.com/desktopBase URL of the update feed and download links - your public storage bucket's domain plus a path prefix (where the release publishes installers, the latest*.yml feeds, and the per-installer .blockmap files). electron-updater polls <url>/latest-mac.yml (macOS), <url>/latest.yml (Windows), and <url>/latest-linux.yml (Linux).

How appId and protocol derive:

  • Leading reverse-DNS labels of appId: from the base URL.
  • Last segment of appId: the protocol slug with hyphens removed (reverse-DNS labels avoid hyphens).
  • protocol: a slug of the app name.

Where it lives: the Electron main and renderer bundles, the CSP policy builder, and the electron-builder packaging config cannot import the env-reading @repo/config index, so config.desktop lives in a committed plain-JS module - packages/config/src/desktop.mjs, exported as @repo/config/desktop - that they all import directly.

Committed config, not env: these values are identical in dev and production. Edit desktop.mjs once (or re-run the CLI) to rebrand the app name, id, scheme, and update feed everywhere. electron-builder reads the same module for the installer's appId, productName, deep-link scheme, and update feed, and the app reads it for the window title and its own identity - so there is no separate sync step and the installer and running app can never disagree. The backend target follows it automatically too: backend-url.ts pins every bridged backend request to the origin from config.desktop.baseUrl (or BASE_URL/PUBLIC_API_URL), so changing baseUrl repoints the app's backend with no hand-edit. The renderer's CSP connect-src names no backend origin - every backend call rides the main-process bridge, not the renderer's network (see Security).

The backend URL is the one per-environment value. Set it with env when you run or build, otherwise it defaults to config.desktop.baseUrl for a build and the local web app in dev:

Env varUsed for
BASE_URLWeb app origin. Overrides config.desktop.baseUrl; in dev it comes from the root .env.
PUBLIC_API_URLHosted backend API URL (defaults to ${BASE_URL}/api)

The derived appId and protocol are sensible defaults you should review. Pure-digit or non-ASCII app names produce odd slugs - a URL scheme cannot start with a digit, and accents are dropped - so edit packages/config/src/desktop.mjs by hand for such names.

On this page