# How to Set Up the OmniRoute Electron Desktop App: Complete Installation Guide

> Easily set up the OmniRoute Electron desktop app with this complete installation guide. Follow simple steps to install dependencies and launch the desktop shell.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-07

---

**To set up the OmniRoute Electron desktop app, install dependencies in both the root and `electron/` directories, then run `npm run dev` from the `electron/` folder to launch the desktop shell with automatic server spawning.**

The OmniRoute Electron wrapper transforms the Next.js web application into a native desktop experience. As implemented in `diegosouzapw/OmniRoute`, this architecture packages a **main process** that manages windows and server lifecycle, a **secure preload script** for IPC communication, and React hooks that let the UI interact with native capabilities without compromising Electron security boundaries.

## Prerequisites and Repository Structure

Before starting, ensure you have Node.js 18+ and npm installed. The Electron-related code lives entirely within the `electron/` directory at the repository root, while the shared React hooks reside in [`src/shared/hooks/useElectron.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/hooks/useElectron.ts).

Key directories to understand:

- [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js) — Main process entry point
- [`electron/preload.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/preload.js) — Secure renderer bridge
- `electron/lib/` — Helper utilities for server management
- `electron/assets/` — Icons and UI resources

## Development Setup

The fastest way to run the OmniRoute Electron desktop app locally requires two terminal sessions.

### Step 1: Start the Next.js Development Server

```bash

# From repository root

npm install
npm run dev

```

This launches the Next.js dev server (default port `20128`). The Electron renderer will poll this endpoint until it responds.

### Step 2: Launch the Electron Shell

```bash

# In a separate terminal

cd electron
npm install
npm run dev

```

The `npm run dev` command in [`electron/package.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/package.json) concurrently starts Electron and waits for the server health check at `http://localhost:20128`. The UI appears only after the server reports ready, preventing blank-screen race conditions.

## Production and Stand-alone Builds

For distribution, build the Next.js app in **standalone mode** so the Electron shell can bundle and spawn it internally.

### Build the Next.js Standalone Output

```bash
npm run build

```

This creates a self-contained server under `.build/next/standalone/` that the Electron main process references via [`electron/lib/serverUrlResolver.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/lib/serverUrlResolver.js).

### Run Production Mode

```bash
cd electron
npm start

```

The main process in [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js) automatically detects whether to spawn the bundled server or connect to a remote instance based on preferences.

## Building Platform-Specific Binaries

Generate installable packages for target operating systems:

```bash
cd electron

# Current platform

npm run build

# Windows (.exe installer + portable)

npm run build:win

# macOS (universal .dmg)

npm run build:mac

# Linux (.AppImage)

npm run build:linux

```

Build artifacts appear in `dist-electron/` at the repository root. The [`electron/package.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/package.json) scripts delegate to `electron-builder` with platform-specific configurations.

## Remote Server Configuration

The OmniRoute Electron desktop app supports connecting to external OmniRoute instances instead of spawning a local server.

### Via Tray Menu

1. Right-click the system tray icon
2. Select **Remote Server → Connect to Remote Server…**
3. Enter the URL (e.g., `http://localhost:20128` or `http://10.0.0.5:20128`)
4. Save preferences to [`electron-preferences.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron-preferences.json) via [`electron/lib/remoteServerPreferences.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/lib/remoteServerPreferences.js)

### Via Environment Variable

Override saved preferences for one-off connections:

```bash
export OMNIROUTE_REMOTE_URL=http://my-remote-host:20128
cd electron
npm start

```

The main process checks `process.env.OMNIROUTE_REMOTE_URL` before consulting persisted preferences, as implemented in the server URL resolution logic.

## Security Architecture

The OmniRoute Electron implementation enforces several security best practices:

- **Content-Security-Policy** — Applied via `session.webRequest.onHeadersReceived` in [`main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/main.js) to restrict `script-src`, `connect-src`, and other directives
- **Context isolation** — The preload script uses `contextBridge.exposeInMainWorld` with an explicit whitelist (`safeInvoke`, `safeSend`, `safeOn`) rather than direct `remote` module access
- **IPC cleanup** — React hooks like `useServerStatus()` and `usePortChanged()` return disposal functions to prevent listener accumulation

The [`src/shared/hooks/useElectron.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/hooks/useElectron.ts) file implements `useSyncExternalStore` for zero-re-render status subscriptions, ensuring efficient UI updates when server state changes.

## Troubleshooting Common Issues

| Symptom | Cause | Solution |
|---------|-------|----------|
| Blank window on startup | Server not responding | Verify `npm run dev` is running in root; check port `20128` availability |
| IPC methods undefined | Preload script failure | Ensure `contextIsolation: true` in [`main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/main.js) BrowserWindow options |
| Remote connection fails | URL protocol mismatch | Use `http://` not `https://` for local network addresses |
| Build produces no output | Missing platform dependencies | Install `electron-builder` prerequisites for target OS |

## Summary

- Install dependencies separately in repository root and `electron/` directory
- Use `npm run dev` in both locations for development with hot-reload
- Build standalone Next.js output with `npm run build` before production packaging
- Generate binaries with `npm run build:*` commands in the `electron/` folder
- Connect to remote servers via tray menu or `OMNIROUTE_REMOTE_URL` environment variable
- Reference [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js) for window lifecycle, [`electron/preload.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/preload.js) for secure IPC, and [`src/shared/hooks/useElectron.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/hooks/useElectron.ts) for UI integration

## Frequently Asked Questions

### What Node.js version does OmniRoute Electron require?

OmniRoute builds successfully on Node.js 18 LTS and newer. The [`electron/package.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/package.json) specifies compatible Electron versions that bundle their own Node runtime, but development tooling in the root relies on system Node.js for the Next.js build pipeline.

### Can I run the desktop app without building the Next.js server first?

For development, yes—run `npm run dev` in the repository root to start the Next.js dev server, then `npm run dev` in `electron/` to attach the desktop shell. For production, you must run `npm run build` first to generate the standalone server bundle that [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js) spawns.

### How does the Electron app know when the server is ready?

The main process polls `http://localhost:<PORT>` with exponential backoff until receiving an HTTP 200 response. Only then does [`main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/main.js) show the BrowserWindow, implemented in the server health monitoring section. This prevents users from seeing a disconnected UI during cold starts.

### Where are remote server preferences stored?

Preferences persist to `<userData>/electron-preferences.json` via [`electron/lib/remoteServerPreferences.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/lib/remoteServerPreferences.js), using Electron's `app.getPath('userData')` directory. The `OMNIROUTE_REMOTE_URL` environment variable takes precedence over this file for temporary overrides.