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, notdist/, becausefile://has no real origin. Fix this on the Vite side — setbase: './'invite.config.tsso Vite emits relative paths — rather than switchingloadModejust for this.'protocol'— registers a customapp://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 a127.0.0.1-only static file server. Slower to start than'protocol', only worth it for Web APIs that check for a literalhttp:/https:scheme — WebUSB, WebBluetooth, WebSerial, and similar device APIs don't accept'protocol''s custom scheme even though it's registered as secure. Configure viaapp.server:port— default0(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