Docs

App & lifecycle configuration

Identity, dev/build URLs, how the renderer is served, window persistence, deep linking, auto-updates, and crash reporting — everything under appId, appName, dev, app, browserWindow, autoUpdater, and crashReporter in electron.config.ts.

Identity

Key Purpose
appId Single-instance lock naming, Windows AUMID, macOS/Windows app name, secureStorage key hashing. Also passed to dae build as electron-builder's appId — no need to duplicate it in electron-builder.config.ts.
appName Also passed to dae build as electron-builder's productName.

Dev workflow (dev)

Key Purpose
dev.url Vite dev server URL that dae run waits on. 'auto' inspects the project's vite.config for server.strictPort: if true, waits on that exact port (Vite either binds there or refuses to start); otherwise starts the dev server itself and reads the real URL back out of Vite's own startup output. Use 'auto' whenever port 5173 might already be taken — a fixed URL would otherwise wait on the wrong port after Vite auto-increments. Default: http://localhost:5173.
dev.openDevTools Open DevTools on launch. Default: true in dev, false in production.

Serving the renderer (app)

app.loadMode picks how the built renderer reaches the window. Production is loaded via win.loadFile() against app.distDir (default 'dist', Vite's default build.outDir) — shared by all three modes.

  • 'file' (default)loadFile() straight off disk. Simplest option, but an absolute-path asset reference (<img src="/logo.png">, common with Vite's default build output) resolves against the filesystem root, not dist/, because file:// has no real origin. Fix this on the Vite side — set base: './' in vite.config.ts so Vite emits relative paths — rather than switching loadMode just for this.
  • 'protocol' — registers a custom app:// scheme backed by a request handler, giving the renderer a real (privileged, secure-context) origin so absolute paths resolve correctly, without running an actual network server. Registration failures are fatal, since falling back would silently change the renderer's origin/security model.
  • 'server' — starts a 127.0.0.1-only static file server. Slower to start than 'protocol', only worth it for Web APIs that check for a literal http:/https: scheme — WebUSB, WebBluetooth, WebSerial, and similar device APIs don't accept 'protocol''s custom scheme even though it's registered as secure. Configure via app.server:
    • port — default 0 (random ephemeral port). Device-permission grants for those Web APIs are origin-scoped (port included), so a random port every launch means re-approving device access every time — set a fixed port if you need it stable. If that port is already taken, startup fails with a clear error instead of silently picking a different one.
    • host — default '127.0.0.1' (loopback only). Only widen this deliberately; it directly grows the app's network attack surface.

Other app keys:

Key Purpose
app.distDir Renderer build output directory, relative to project root. Default 'dist'.
app.singleInstance Prevent launching more than one instance; second launch focuses the existing window. Default true.
app.persistWindowState Remember window size/position between launches. Default false.
app.deepLinkingScheme Custom URL protocol for deep linking (e.g. 'myapp'myapp://). Disabled by default.
app.appLauncherSchemes Additional custom schemes (beyond deepLinkingScheme) window.Electron.protocols may register as default handler for. Default [].
app.externalWindowAllowedSchemes Non-web schemes external managed windows may hand off to shell.openExternal. Dangerous script/data schemes are ignored. Default [].

Window options (browserWindow)

Pass-through for BrowserWindowConstructorOptions: width, height, minWidth, minHeight, icon, webPreferences, and any other Electron BrowserWindow option. preload, contextIsolation, and nodeIntegration inside webPreferences are managed by this package and not configurable — the bridge depends on them.

browserWindow: {
  width: 1200,
  height: 800,
},

Auto-updater (autoUpdater)

electron-updater-backed checks, only active in production (app.isPackaged) — does nothing under dae run.

Key Default
enabled false
channel 'latest' | 'beta' | 'alpha'
autoDownload
autoInstallOnQuit
allowPrerelease
allowDowngrade

The renderer drives it via window.Electron.updater.checkForUpdate(), downloadUpdate(), quitAndInstall(), and on(event, callback) — see Usage.

Crash reporting (crashReporter)

Off by default — this is a decision about where crash dumps go, not something to enable silently.

Key Purpose
enabled Default false.
submitURL Remote endpoint (your own Sentry/Backtrace/...) that collects reports. Omit to only collect dumps locally, readable via window.Electron.crashReporter.getLastCrashReport(), without uploading anywhere.
uploadToServer Upload to submitURL automatically. Default true when submitURL is set.
companyName, extra Metadata attached to every crash report.

Minimal example

import type { ElectronConfig } from '@devioarts/electron';

const config: ElectronConfig = {
  appId: 'com.example.app',
  appName: 'My App',

  dev: {
    url: 'http://localhost:5173',
    openDevTools: true,
  },

  app: {
    loadMode: 'file',
    distDir: 'dist',
    singleInstance: true,
    persistWindowState: true,
  },

  browserWindow: {
    width: 1200,
    height: 800,
  },
};

export default config;

This is templates/electron.config.ts (scaffolded by dae init, minus the UI section — see UI configuration). playground/electron.config.ts is a working example that additionally sets appId: 'com.devioarts.electron.demo' and appName: 'electron-demo'.

Next: Security configuration · UI configuration · Processes configuration

Last updated on July 17, 2026