# How the OmniRoute Electron Desktop Application Connects to the Backend Server

> Learn how the OmniRoute Electron desktop app connects to its backend server locally or remotely. Explore connection modes and configuration details for seamless integration.

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

---

**The OmniRoute Electron desktop app connects to its backend server in two modes: local (spawning a bundled Next.js server on localhost:20128) or remote (connecting to an external URL resolved from environment variables or persisted preferences).**

The OmniRoute desktop application is built with Electron and offers flexible backend connectivity to support both standalone deployment and remote server scenarios. Understanding how the Electron shell establishes this connection is essential for operators configuring containerized, LAN-hosted, or cloud-based deployments.

## Local Mode: Embedded Next.js Server

By default, the OmniRoute Electron application runs in **local mode**, spawning its own backend server.

When no remote URL is configured, the main process executes `startNextServer()` in [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js) (lines 41-46) to launch the bundled Next.js server. The default port is **20128**, stored in the `serverPort` variable, and the server URL is constructed by `getServerUrl()` as `http://localhost:${serverPort}`.

The main window then loads this local URL (line 95 in [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js)). The application waits for server readiness using the polling logic in [`electron/lib/serverReadiness.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/lib/serverReadiness.js) before rendering the UI, ensuring the backend is fully initialized.

## Remote Mode: External Server Connection

The Electron shell can connect to any reachable OmniRoute instance through **remote mode**, configured through two priority sources.

### URL Resolution Priority

As implemented in [`electron/lib/resolveRemoteServerUrl.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/lib/resolveRemoteServerUrl.js) (lines 18-44), the remote URL resolves in this order:

1. **`OMNIROUTE_REMOTE_URL` environment variable** — highest priority, useful for Docker or automated deployments
2. **[`electron-preferences.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron-preferences.json) file** — persists user selections from the "Connect to Remote Server…" dialog

When `resolveRemoteServerUrl()` returns a valid HTTP(S) URL, it is stored in `remoteServerUrl`. The `getServerUrl()` function then returns this remote address instead of the localhost URL.

### Server Behavior in Remote Mode

In [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js) (lines 42-52), `startNextServer()` checks `remoteServerUrl` before spawning:

- If **defined** — logs the remote connection, notifies the renderer that the app is "running," and **does not launch** the local server
- If **undefined** — spawns the local Next.js server using the bundled `nodeExecutable` and `serverScript`

This prevents port conflicts and resource consumption when an external backend is available.

## User-Driven Remote Configuration

OmniRoute provides a tray menu option that opens the **"Connect to Remote Server…"** dialog for interactive configuration.

### Configuration Flow

- The tray menu opens `remoteServerPromptWindow`, implemented in [`electron/assets/remoteServerPrompt.html`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/assets/remoteServerPrompt.html) with preload script [`electron/remoteServerPromptPreload.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/remoteServerPromptPreload.js)
- The user submits a URL via IPC channel `remote-server-prompt:submit`
- `setRemoteServerUrl()` validates the URL with `isValidHttpUrl()`
- Valid URLs are persisted through `writeRemoteServerUrl()` in [`electron/lib/remoteServerPreferences.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/lib/remoteServerPreferences.js) (lines 48-66)
- The application restarts to apply the new connection mode

Submitting an empty string clears the remote setting and reverts to local mode.

### Preferences Persistence

The preferences file location is determined at runtime:

```js
const REMOTE_SERVER_PREFS_PATH = path.join(
  resolveDataDir(null, process.env),
  "electron-preferences.json"
);

```

This ensures the remote URL survives application restarts without requiring environment variable configuration.

## Connection Information for the Renderer

The renderer process queries connection state through the `get-app-info` IPC handler. This returns `remoteServerUrl` among other metadata, allowing the frontend to display the current backend endpoint and adjust behavior accordingly.

## Practical Code Examples

### Force remote server via environment variable

```js
// For containerized or automated deployments
process.env.OMNIROUTE_REMOTE_URL = "https://my-omniroute.example.com";
app.relaunch(); // Restart to pick up the new value

```

### Change remote URL from renderer (UI interaction)

```js
// Fetch current configuration
await window.electron.ipcRenderer.invoke("remote-server-prompt:get-initial-url");

// Submit new remote endpoint
await window.electron.ipcRenderer.send(
  "remote-server-prompt:submit",
  "https://other-host:20128"
);

```

### Clear remote setting (re-enable local server)

```js
// Empty string clears persisted preference
await window.electron.ipcRenderer.invoke("remote-server-prompt:submit", "");

```

## Key Source Files

| File | Purpose |
|------|---------|
| [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js) | Core Electron process: URL determination, server spawning, IPC handlers, window management |
| [`electron/lib/resolveRemoteServerUrl.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/lib/resolveRemoteServerUrl.js) | Resolves remote URL from environment or preferences with defined priority order |
| [`electron/lib/remoteServerPreferences.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/lib/remoteServerPreferences.js) | JSON read/write operations for persistent remote server configuration |
| [`electron/remoteServerPromptPreload.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/remoteServerPromptPreload.js) | Preload script exposing safe APIs to the remote server configuration dialog |
| [`electron/assets/remoteServerPrompt.html`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/assets/remoteServerPrompt.html) | Modal UI for entering remote server URLs |
| [`electron/lib/serverReadiness.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/lib/serverReadiness.js) | Health endpoint polling before presenting the application UI |

## Summary

- **Two connection modes**: Local (embedded Next.js on port 20128) or remote (any HTTP(S) OmniRoute instance)
- **Remote resolution priority**: `OMNIROUTE_REMOTE_URL` environment variable → [`electron-preferences.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron-preferences.json) file
- **Local server spawning**: Controlled by `startNextServer()` in [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js), skipped entirely when remote URL is configured
- **Interactive configuration**: Tray menu provides UI-driven remote setup with URL validation and persistence
- **Renderer access**: Connection state available via `get-app-info` IPC handler for UI adaptation

This architecture gives operators deployment flexibility ranging from single-user desktop installations to multi-user remote server configurations.

## Frequently Asked Questions

### How do I force the OmniRoute Electron app to use a remote backend?

Set the `OMNIROUTE_REMOTE_URL` environment variable to your target URL and restart the application. This takes precedence over any persisted preferences and is useful for Docker deployments or automated testing environments.

### Where does OmniRoute store the remote server configuration?

The remote URL is persisted in [`electron-preferences.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron-preferences.json) within the application's data directory, returned by `resolveDataDir()`. This path varies by platform but ensures settings survive application restarts.

### Can I switch from remote back to local mode without reinstalling?

Yes. Open the "Connect to Remote Server…" dialog from the tray menu and submit an empty URL, or programmatically send an empty string to the `remote-server-prompt:submit` IPC channel. This clears the preference and restarts the app in local mode.

### What happens if the configured remote server is unreachable?

The `startNextServer()` function only validates URL format through `isValidHttpUrl()`, not connectivity. The application will attempt to load the remote URL and may display connection errors in the renderer. Health checking for remote endpoints should be handled at the infrastructure or monitoring layer.