How Modly's Settings Store Persists and Synchronizes Configuration

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 file located within the Electron userData path (retrieved via app.getPath('userData')). The settings store (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 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.

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:

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:

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 bridges renderer requests to the settings store:

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 inside Electron's userData directory, retrieved via app.getPath('userData').
  • Store Implementation: The 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 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 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.

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 →