# How to Set Up the FreeLLMAPI Desktop App: Complete Build Guide

> Learn how to set up the FreeLLMAPI desktop app. Follow our complete build guide to run a local OpenAI-compatible API endpoint easily on your machine. Get started now!

- Repository: [Tashfeen/freellmapi](https://github.com/tashfeenahmed/freellmapi)
- Tags: how-to-guide
- Published: 2026-06-28

---

**TLDR:** FreeLLMAPI provides a native Electron menu-bar application that bundles the Express router and React dashboard, enabling you to run a local OpenAI-compatible API endpoint on `127.0.0.1:31415` by building from the `desktop/` directory using Node.js and standard C++ toolchains.

The FreeLLMAPI desktop application is a self-contained, native menu-bar app that runs the full inference router locally alongside a React-based dashboard. Located in the `desktop/` directory of the tashfeenahmed/freellmapi repository, this Electron-based package compiles directly from the same monorepo source that powers the Docker image and web UI. This guide covers the architecture, build prerequisites, and step-by-step commands required to compile and launch the app on macOS and Windows.

## Architecture Overview

The desktop app bundles three core components into a single native experience:

1. **Electron main process** – Handles the tray icon, native window management, and boots the Express server. This logic resides in [`desktop/src/main.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/desktop/src/main.ts).
2. **Renderer process** – A glass-styled HTML pop-over ([`desktop/renderer/popover.html`](https://github.com/tashfeenahmed/freellmapi/blob/main/desktop/renderer/popover.html)) that displays live request statistics and a copy-button for the unified API key.
3. **Shared server code** – The identical OpenAI-compatible router used by the Docker image, located at [`server/src/services/router.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/router.ts). The desktop build imports this via the `FREEAPI_REPO` environment variable.

Data persistence uses **SQLite** (`better-sqlite3`) compiled against Electron’s ABI. Keys and analytics are stored in platform-specific application-support folders, while the `npm run rebuild:native` script in [`desktop/package.json`](https://github.com/tashfeenahmed/freellmapi/blob/main/desktop/package.json) automates the native addon compilation.

## Prerequisites

Before building, ensure your system has the required native compilation tools:

- **macOS:** Xcode Command Line Tools (`xcode-select --install`).
- **Windows:** Visual Studio Build Tools with the *Desktop development with C++* workload.
- **Both:** Node.js 20+ (recommended to use `nvm` or `fnm`).
- **Optional:** Docker is only required if you prefer a pre-built binary installer; it is not needed for local compilation.

The build process must compile the `better-sqlite3` native module against Electron’s specific ABI version, which the provided npm scripts handle automatically.

## Building the Desktop App

From the **repository root** (the folder containing the monorepo [`package.json`](https://github.com/tashfeenahmed/freellmapi/blob/main/package.json)), execute the following commands:

```bash

# Install dependencies for all workspace packages (server, client, desktop)

npm install

# Build the macOS installer (.dmg)

npm run desktop:dist

# Build the Windows installer (.exe)

npm run desktop:dist:win

```

These commands trigger the Electron Builder configuration defined in [`desktop/electron-builder.yml`](https://github.com/tashfeenahmed/freellmapi/blob/main/desktop/electron-builder.yml). The process compiles the React UI, bundles the Express router, compiles native dependencies, and outputs a signed (or unsigned) installer to `desktop/dist-electron/`.

**Note:** Locally built installers are unsigned. On macOS, you may need to right-click and select *Open* to bypass Gatekeeper; on Windows, click *More info* → *Run anyway* in the SmartScreen dialog.

## Running the App in Development Mode

For iterative development without packaging, use the development workflow:

```bash
cd desktop
npm install
npm run rebuild:native  # Compile better-sqlite3 for Electron's ABI

npm run dev            # Launches the Electron app with hot-reload

```

Set the `FREEAPI_REPO` environment variable to point to a different server checkout if needed. Alternatively, run `npm run desktop:dev` from the repository root to build the client assets first (`npm run build -w client`) and then launch the desktop dev server in one step.

## Data Storage and Configuration

The desktop server binds exclusively to `127.0.0.1:31415` by default, ensuring isolation from the network unless explicitly exposed. Persistent data is stored in the following locations:

- **macOS:** `~/Library/Application Support/FreeLLMAPI/`
- **Windows:** `%APPDATA%\FreeLLMAPI\`

These directories contain the SQLite database, encrypted provider API keys, request analytics, and the auto-generated `ENCRYPTION_KEY` file. You can customize the listening port by editing [`desktop/src/config.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/desktop/src/config.ts) or setting the `PORT` environment variable before launch.

## Using the Unified API Key

Once the menu-bar icon is active, click it and select **Open Dashboard** to access the full React UI. Add your free-tier provider credentials in the **Keys** section; these are encrypted and stored locally. Copy the unified `freellmapi-…` key from the header to use with any OpenAI-compatible client:

```python
from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:31415/v1",
    api_key="freellmapi-your-unified-key",
)

response = client.chat.completions.create(
    model="auto",
    messages=[{"role": "user", "content": "Explain quantum computing"}],
)
print(response.choices[0].message.content)

```

## Summary

- The FreeLLMAPI desktop app is an Electron-based menu-bar application that bundles the Express router ([`server/src/services/router.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/services/router.ts)) and React dashboard into a single native binary.
- Build the installer from the repository root using `npm run desktop:dist` (macOS) or `npm run desktop:dist:win` (Windows), which compiles the native `better-sqlite3` addon and packages everything via [`desktop/electron-builder.yml`](https://github.com/tashfeenahmed/freellmapi/blob/main/desktop/electron-builder.yml).
- For development, run `npm run rebuild:native` followed by `npm run dev` inside the `desktop/` directory to enable hot-reloading.
- Data persists in platform-specific application-support folders (`~/Library/Application Support/FreeLLMAPI/` or `%APPDATA%\FreeLLMAPI\`), with the server binding to `127.0.0.1:31415` by default.

## Frequently Asked Questions

### Do I need Docker to run the desktop app?

No. Docker is only required if you want to use a pre-built binary installer from the releases page. Building locally requires only Node.js and a C/C++ toolchain (Xcode CLT on macOS or Visual Studio Build Tools on Windows) to compile the native `better-sqlite3` dependency.

### Where is the encryption key stored?

The app generates an `ENCRYPTION_KEY` on first launch and saves it alongside the SQLite database in the platform-specific application-support folder (`~/Library/Application Support/FreeLLMAPI/` on macOS or `%APPDATA%\FreeLLMAPI\` on Windows). You can also set this key manually via environment variables before starting the app.

### Can I change the listening port from 31415?

Yes. The desktop server binds to `127.0.0.1:31415` by default. To use a different port, either edit [`desktop/src/config.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/desktop/src/config.ts) or set the `PORT` environment variable before launching the application (e.g., `PORT=8080 npm run dev`).

### Is the desktop version compatible with the web dashboard?

Yes. Both interfaces use the identical server code and share the same SQLite store. Any changes made in the desktop dashboard—such as adding provider keys or reordering the fallback chain—are immediately reflected in the web UI if you run it, and vice versa, because they both read from the same local database.