# How Fluxer Manages User Data Paths and Desktop Configuration Persistence

> Learn how Fluxer manages user data paths and desktop configuration persistence using channel-specific userData directories and JSON files for robust settings management.

- Repository: [Fluxer/fluxer](https://github.com/fluxerapp/fluxer)
- Tags: internals
- Published: 2026-03-17

---

**Fluxer isolates per-user data into channel-specific Electron `userData` directories and persists desktop settings via JSON files stored in that location.**

Fluxer is an Electron-based desktop application that separates user data by release channel to prevent configuration conflicts between stable and canary builds. The application determines where to store settings at runtime using a dedicated path resolution system. Understanding how Fluxer manages user data paths and desktop configuration persistence is essential for debugging installation issues or extending the app's configuration capabilities.

## Channel-Specific User Data Directories

Fluxer stores all per-user data in a dedicated **Electron `userData`** directory chosen at runtime based on the build channel. During startup, the main process calls `configureUserDataPath()` located in [`fluxer_desktop/src/common/UserDataPath.tsx`](https://github.com/fluxerapp/fluxer/blob/main/fluxer_desktop/src/common/UserDataPath.tsx) to establish the storage location.

The function executes a five-step resolution process:

1. **Reads** the compile-time `BUILD_CHANNEL` constant.
2. **Maps** the channel to a folder name via `channelStorageDirectoryMap` (`fluxer` for stable, `fluxercanary` for canary).
3. **Builds** an absolute path under the OS-provided app-data directory using `app.getPath('appData')`.
4. **Sets** the Electron userData path via `app.setPath('userData', base)` so all subsequent API calls point to that folder.
5. **Returns** the resolved `channel`, `directoryName`, and `base` path for logging and downstream use.

```typescript
// fluxer_desktop/src/common/UserDataPath.tsx
export function configureUserDataPath(): UserDataPaths {
  const channel = BUILD_CHANNEL;
  const {directoryName, base} = resolveUserDataPaths(channel);
  app.setPath('userData', base);          // ← centralise all user-data here
  return {channel, directoryName, base};
}

```

Because the `userData` folder is tied to the channel, stable and canary installations maintain completely separate sets of settings, caches, and window-state files, preventing cross-contamination.

## Persisting Desktop Configuration to JSON

All desktop-wide settings are persisted inside the resolved userData directory as individual JSON files.

### Application Settings Storage

The **custom app URL** and other preferences live in [`settings.json`](https://github.com/fluxerapp/fluxer/blob/main/settings.json). The [`fluxer_desktop/src/common/DesktopConfig.tsx`](https://github.com/fluxerapp/fluxer/blob/main/fluxer_desktop/src/common/DesktopConfig.tsx) module handles persistence through two primary functions:

- **`loadDesktopConfig(userDataPath)`**: Reads the JSON file on application launch.
- **`setCustomAppUrl(url)`**: Writes configuration changes back to disk via `saveDesktopConfig()`.

```typescript
// fluxer_desktop/src/common/DesktopConfig.tsx
export function loadDesktopConfig(userDataPath: string): void {
  configPath = path.join(userDataPath, CONFIG_FILE_NAME);
  if (fs.existsSync(configPath)) {
    const data = fs.readFileSync(configPath, 'utf-8');
    config = JSON.parse(data);
  }
}

export function setCustomAppUrl(appUrl: string | null): void {
  if (appUrl) config.app_url = appUrl; else delete config.app_url;
  saveDesktopConfig();                     // writes back to settings.json
}

```

### Window State Management

**Window size and position** persist to [`window-state.json`](https://github.com/fluxerapp/fluxer/blob/main/window-state.json). The [`fluxer_desktop/src/main/Window.tsx`](https://github.com/fluxerapp/fluxer/blob/main/fluxer_desktop/src/main/Window.tsx) module computes the file path using `getWindowStateFile()`, which concatenates `app.getPath('userData')` with the filename. On window close or resize, the application writes the `WindowBounds` object; on startup, it restores the bounds only if they remain valid for the current display configuration.

```typescript
// fluxer_desktop/src/main/Window.tsx (excerpt)
function getWindowStateFile(): string {
  if (!windowStateFile) {
    const userDataPath = app.getPath('userData');
    windowStateFile = path.join(userDataPath, 'window-state.json');
  }
  return windowStateFile;
}

```

## Startup Initialization Sequence

The entry point in [`fluxer_desktop/src/main/index.tsx`](https://github.com/fluxerapp/fluxer/blob/main/fluxer_desktop/src/main/index.tsx) orchestrates the initialization order to ensure the environment is configured before loading persisted state:

```typescript
// fluxer_desktop/src/main/index.tsx (excerpt)
const userDataConfig = configureUserDataPath();   // ← pick folder
log.info('Configured user data storage', userDataConfig);
loadDesktopConfig(userDataConfig.base);          // ← load settings.json

```

This sequence guarantees that `app.getPath('userData')` returns the correct channel-specific directory before any configuration files are accessed.

## Working with User Data Paths in Practice

To read or write custom configuration files alongside Fluxer's built-in settings, reference the resolved userData path:

```typescript
// Example: manually persisting a new setting
import fs from 'node:fs';
import path from 'node:path';
import {app} from 'electron';

function saveMyFlag(value: boolean) {
  const file = path.join(app.getPath('userData'), 'my-flag.json');
  fs.writeFileSync(file, JSON.stringify({enabled: value}), 'utf-8');
}

```

To override the application URL for local development:

```typescript
import {configureUserDataPath} from '@electron/common/UserDataPath';
import {setCustomAppUrl, getAppUrl} from '@electron/common/DesktopConfig';

const paths = configureUserDataPath();   // sets app.getPath('userData')
setCustomAppUrl('http://localhost:5173');

console.log('Running URL →', getAppUrl());

```

## Summary

- **Channel isolation**: Fluxer uses `configureUserDataPath()` to create separate directories for stable (`fluxer`) and canary (`fluxercanary`) builds, preventing settings leakage between channels.
- **Centralized resolution**: The `userData` path is set once at startup via `app.setPath()`, ensuring all Electron APIs and custom code reference the same base directory.
- **JSON persistence**: Desktop configuration ([`settings.json`](https://github.com/fluxerapp/fluxer/blob/main/settings.json)) and window state ([`window-state.json`](https://github.com/fluxerapp/fluxer/blob/main/window-state.json)) are stored as plain JSON files within the userData directory.
- **Deterministic initialization**: The main process resolves the data path before loading any configuration, guaranteeing consistent file access throughout the application lifecycle.

## Frequently Asked Questions

### Where does Fluxer store user data on disk?

Fluxer stores user data in a channel-specific subdirectory under the operating system's standard application data folder. On Windows, this is typically `%APPDATA%/fluxer` or `%APPDATA%/fluxercanary`; on macOS, `~/Library/Application Support/fluxer` or `~/Library/Application Support/fluxercanary`. The exact path is determined at runtime by `configureUserDataPath()` in [`fluxer_desktop/src/common/UserDataPath.tsx`](https://github.com/fluxerapp/fluxer/blob/main/fluxer_desktop/src/common/UserDataPath.tsx).

### How do stable and canary builds keep settings separate?

The build channel (defined by the `BUILD_CHANNEL` constant at compile time) maps to a specific directory name via `channelStorageDirectoryMap`. Stable builds use the `fluxer` folder, while canary builds use `fluxercanary`. Because Electron's `userData` path is set to this channel-specific folder during startup, each channel maintains independent [`settings.json`](https://github.com/fluxerapp/fluxer/blob/main/settings.json) and [`window-state.json`](https://github.com/fluxerapp/fluxer/blob/main/window-state.json) files.

### Can I manually edit Fluxer configuration files?

Yes. Because Fluxer persists configuration as plain JSON files ([`settings.json`](https://github.com/fluxerapp/fluxer/blob/main/settings.json) and [`window-state.json`](https://github.com/fluxerapp/fluxer/blob/main/window-state.json)) in the userData directory, you can manually edit these files when the application is not running. Changes take effect on the next launch, though invalid JSON or malformed window bounds may cause the application to fall back to default values.

### What happens to window position if the display configuration changes?

When restoring window bounds from [`window-state.json`](https://github.com/fluxerapp/fluxer/blob/main/window-state.json), Fluxer validates that the saved coordinates are still within the bounds of the current display configuration. If the display has been disconnected or the resolution changed such that the window would appear off-screen, the application discards the persisted state and uses default dimensions instead.