How the OmniRoute Electron Desktop Application Connects to the Backend Server

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 (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). The application waits for server readiness using the polling logic in 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 (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 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 (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

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

Preferences Persistence

The preferences file location is determined at runtime:

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

// 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)

// 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)

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

Key Source Files

File Purpose
electron/main.js Core Electron process: URL determination, server spawning, IPC handlers, window management
electron/lib/resolveRemoteServerUrl.js Resolves remote URL from environment or preferences with defined priority order
electron/lib/remoteServerPreferences.js JSON read/write operations for persistent remote server configuration
electron/remoteServerPromptPreload.js Preload script exposing safe APIs to the remote server configuration dialog
electron/assets/remoteServerPrompt.html Modal UI for entering remote server URLs
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 file
  • Local server spawning: Controlled by startNextServer() in 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →