# How Modly's Settings Store Persists and Synchronizes Configuration

> Discover how Modly persists configuration to a JSON file and synchronizes state across processes with IPC handlers. Ensure immediate reflection of changes in all renderer windows.

- Repository: [lightningpixel/modly](https://github.com/lightningpixel/modly)
- Tags: internals
- Published: 2026-08-15

---

**Modly persists configuration to a JSON file in Electron's user data directory and synchronizes state across processes using IPC handlers, ensuring all renderer windows reflect changes immediately.**

The `lightningpixel/modly` repository implements a lightweight, file-backed configuration system that balances durability with real-time consistency. Unlike database-heavy solutions, Modly uses a simple JSON store combined with Electron's inter-process communication (IPC) to keep settings synchronized between the main process and multiple renderer windows.

## JSON File Persistence Architecture

All user-specific configuration resides in a [`settings.json`](https://github.com/lightningpixel/modly/blob/main/settings.json) file located within the Electron `userData` path (retrieved via `app.getPath('userData')`). The **settings store** ([`electron/main/settings-store.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/settings-store.ts)) serves as the single source of truth for directory paths and authentication tokens.

### Default Configuration with Migration

The `getSettings(userData)` function constructs default locations for models, workspaces, workflows, extensions, and dependencies. When [`settings.json`](https://github.com/lightningpixel/modly/blob/main/settings.json) exists, the function reads and merges it with these defaults, automatically migrating legacy keys such as the deprecated `outputsDir` property. This ensures backward compatibility while always returning a complete `AppSettings` object.

### Atomic Write Operations

Updates occur through `setSettings(userData, patch)`, which accepts a `Partial<AppSettings>` object. The function first retrieves the current configuration via `getSettings`, applies the patch, and writes the result back to disk using `writeFileSync` with two-space indentation. Because the write is synchronous and atomic, any subsequent read operation—whether from the same process or a newly launched instance—immediately sees the latest values.

## Cross-Process Synchronization via IPC

Renderer processes never access the filesystem directly. Instead, they communicate with the main process through IPC handlers defined in [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts).

### IPC Handler Implementation

The main process exposes two critical channels:
- **`getSettings`** – Returns the current `AppSettings` object by calling the store's `getSettings` function.
- **`setSettings`** – Receives a partial settings object from the renderer, invokes `setSettings(userData, patch)` to persist the change, and returns the updated configuration.

### Real-Time Broadcast Mechanism

When `setSettings` is invoked, the main process writes the JSON file and immediately broadcasts the new configuration back to the requesting renderer. This broadcast extends to all open windows, ensuring that path changes, token updates, and directory relocations remain consistent across the entire application without requiring manual refreshes.

## Practical Usage Examples

### Reading Configuration from the Renderer

To retrieve the current settings from a React component or other renderer context:

```typescript
import { ipcRenderer } from 'electron'

async function loadSettings() {
  const settings = await ipcRenderer.invoke('getSettings')
  console.log('Current Modly settings:', settings)
}

loadSettings()

```

### Updating Values (e.g., Hugging Face Token)

To modify a specific setting such as the Hugging Face authentication token:

```typescript
import { ipcRenderer } from 'electron'

async function updateToken(newToken: string) {
  const updated = await ipcRenderer.invoke('setSettings', { hfToken: newToken })
  console.log('Settings after update:', updated)
}

updateToken('hf_XXXXXXXXXXXXXXXX')

```

### Behind the Scenes: Main Process Handlers

The IPC implementation in [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts) bridges renderer requests to the settings store:

```typescript
import { ipcMain, app } from 'electron'
import { getSettings, setSettings } from './settings-store'

ipcMain.handle('getSettings', (event) => {
  const userData = app.getPath('userData')
  return getSettings(userData)
})

ipcMain.handle('setSettings', (event, patch) => {
  const userData = app.getPath('userData')
  return setSettings(userData, patch)
})

```

## Summary

- **File Location**: Modly stores configuration in [`settings.json`](https://github.com/lightningpixel/modly/blob/main/settings.json) inside Electron's `userData` directory, retrieved via `app.getPath('userData')`.
- **Store Implementation**: The [`electron/main/settings-store.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/settings-store.ts) file provides `getSettings` and `setSettings` functions that handle defaults, legacy migrations, and atomic file writes.
- **Synchronization**: IPC handlers in [`electron/main/ipc-handlers.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/ipc-handlers.ts) expose these functions to renderers, broadcasting updates to all windows immediately after persistence.
- **Durability**: Using `writeFileSync` ensures data survives application restarts, while the merge-based approach preserves settings across version updates.

## Frequently Asked Questions

### Where is the Modly settings.json file located on disk?

The file resides in the Electron user data directory, which varies by operating system. On Windows, this is typically `%APPDATA%/Modly/settings.json`; on macOS, `~/Library/Application Support/Modly/settings.json`; and on Linux, `~/.config/Modly/settings.json`. The exact path is determined at runtime by `app.getPath('userData')`.

### How does Modly keep multiple windows synchronized when settings change?

When any renderer invokes `setSettings` via IPC, the main process writes the updated configuration to disk and immediately returns the new state to the caller. The architecture ensures that subsequent `getSettings` calls from other windows retrieve the latest values, maintaining consistency without requiring a separate state management library.

### What happens if the settings.json file becomes corrupted?

The `getSettings` function in [`electron/main/settings-store.ts`](https://github.com/lightningpixel/modly/blob/main/electron/main/settings-store.ts) validates the existing file against default configuration objects. If parsing fails or keys are missing, the function merges the corrupted data with sensible defaults, effectively repairing the configuration on the next read operation without losing user data.

### Can two processes write to the settings simultaneously?

Because Modly uses `writeFileSync` for atomic writes and follows a single-writer pattern (only the main process writes to disk), simultaneous write conflicts are prevented. Renderer processes always route updates through the main process's IPC handlers, serializing access to the configuration file and eliminating race conditions.