# How PowerToys Settings v2 Works: JSON Configuration and IPC Architecture

> Discover how PowerToys Settings v2 uses JSON configuration and IPC to synchronize changes between the UI and runner process. Understand the internal workings of this essential Windows utility.

- Repository: [Microsoft/PowerToys](https://github.com/microsoft/PowerToys)
- Tags: internals
- Published: 2026-02-25

---

**PowerToys Settings v2 stores module configurations as JSON files in `%LOCALAPPDATA%\Microsoft\PowerToys\` and synchronizes changes between the Settings UI and the runner process via a named-pipe, two-way IPC channel.**

The PowerToys Settings v2 system provides a robust architecture for managing module configurations through JSON persistence and real-time inter-process communication. This architecture separates the Settings UI process from the runner process while ensuring configuration changes propagate instantly across the application. Understanding how PowerToys Settings v2 handles JSON configuration and IPC is essential for developers extending PowerToys or debugging configuration issues.

## JSON Configuration Storage and Retrieval

### The SettingsRepository Pattern

PowerToys Settings v2 centralizes configuration access through the generic `SettingsRepository<T>` class located in `src/settings-ui/Settings.UI.Library/SettingsRepository[`1.cs`](https://github.com/microsoft/PowerToys/blob/main/1.cs). This repository implements a singleton pattern that caches settings objects in memory while coordinating persistence operations.

When a view model requests configuration data, `SettingsRepository<T>.GetInstance(SettingsUtils.Default).GetSettings()` returns the strongly-typed settings object. The generic type parameter `T` must implement `ISettingsConfig`, ensuring consistent serialization behavior across all PowerToys modules.

### File I/O with SettingsUtils

The actual file operations occur in [`src/settings-ui/Settings.UI.Library/SettingsUtils.cs`](https://github.com/microsoft/PowerToys/blob/main/src/settings-ui/Settings.UI.Library/SettingsUtils.cs). The `GetSettings<T>(string moduleName, string fileName)` method constructs the path `%LOCALAPPDATA%\Microsoft\PowerToys\<moduleName>\<fileName>.json`, creating the file with default values if missing.

```csharp
// Example: Loading FancyZones settings
var fancyZonesSettings = SettingsRepository<FancyZonesSettings>.GetInstance(
    SettingsUtils.Default).GetSettings();
bool isEnabled = fancyZonesSettings.Enabled;

```

This utility handles JSON deserialization using `System.Text.Json`, converting the flat file structure into the hierarchical C# objects used by the view models.

## Two-Way IPC Communication Architecture

### Sending Changes from Settings UI to Runner

When users modify settings through the XAML interface, view models serialize the entire configuration object and transmit it via a named pipe. The entry point for this operation is `ShellPage.SendDefaultIPCMessage` in [`src/settings-ui/Settings.UI/SettingsXAML/Views/ShellPage.xaml.cs`](https://github.com/microsoft/PowerToys/blob/main/src/settings-ui/Settings.UI/SettingsXAML/Views/ShellPage.xaml.cs).

The [`MainWindow.xaml.cs`](https://github.com/microsoft/PowerToys/blob/main/MainWindow.xaml.cs) file initializes the static callback `ShellPage.DefaultSndMSGCallBack` during application startup, establishing the communication channel with the runner process.

```csharp
// ViewModel implementation pattern
private void OnEnabledChanged(bool newValue)
{
    _settings.Enabled = newValue;
    var payload = _settings.ToJsonString();
    _sendMessage(payload); // Calls ShellPage.SendDefaultIPCMessage
}

```

The JSON payload travels through the named pipe to the runner process, where `Program.IPCMessageReceivedCallback` handles the incoming message.

### Receiving and Processing Messages in the Runner

The runner process registers a global callback in `Program.IPCMessageReceivedCallback` that parses the JSON and dispatches it to the appropriate module. Each module registers a handler in `ShellPage.ShellHandler.IPCResponseHandleList` during initialization.

```csharp
// Runner-side message handling pattern
Program.IPCMessageReceivedCallback = (msg) =>
{
    var json = JsonObject.Parse(msg);
    foreach (var handle in ShellPage.ShellHandler.IPCResponseHandleList)
    {
        handle(json);
    }
};

```

For C++ modules, the handler invokes `set_config` as declared in [`src/modules/interface/powertoy_module_interface.h`](https://github.com/microsoft/PowerToys/blob/main/src/modules/interface/powertoy_module_interface.h). C# modules like PowerRename implement `SetConfig` directly to parse the JSON and update internal state.

### Bidirectional Communication and Feedback

The IPC channel supports full duplex communication. The runner can send status updates, hotkey conflict notifications, or enable/disable commands back to the Settings UI. These messages follow the same JSON format and travel through the identical named pipe infrastructure.

When the runner sends feedback, the registered handlers in `IPCResponseHandleList` update the view models, which then propagate changes to the XAML bindings. This ensures the UI remains synchronized with the actual module state regardless of which process initiated the change.

## Data Flow and Persistence Lifecycle

The complete configuration lifecycle demonstrates how PowerToys Settings v2 maintains consistency across processes:

1. **Initial Load**: `SettingsRepository<T>` reads JSON from disk via `SettingsUtils` when the Settings UI starts
2. **User Modification**: View models update the in-memory settings object and serialize to JSON
3. **IPC Transmission**: `ShellPage.SendDefaultIPCMessage` writes the JSON to the named pipe
4. **Runner Processing**: `Program.IPCMessageReceivedCallback` parses the JSON and dispatches to the module's `set_config` or `SetConfig` method
5. **Module Application**: The module applies the configuration changes to its internal state
6. **Disk Persistence**: The runner may write the configuration back to disk through its own `SettingsUtils` instance
7. **Feedback Loop**: Optional runner-to-UI messages update the view models to confirm application

This architecture ensures that the JSON files in `%LOCALAPPDATA%\Microsoft\PowerToys\` always represent the source of truth, while the IPC channel provides real-time synchronization between the Settings UI and the runner process.

## Implementation Examples

### Loading Settings in a ViewModel

```csharp
using Microsoft.PowerToys.Settings.UI.Library;

public class MyModuleViewModel
{
    private readonly MyModuleSettings _settings;
    
    public MyModuleViewModel()
    {
        _settings = SettingsRepository<MyModuleSettings>.GetInstance(
            SettingsUtils.Default).GetSettings();
    }
    
    public bool IsEnabled
    {
        get => _settings.Enabled;
        set
        {
            _settings.Enabled = value;
            SendSettingsUpdate();
        }
    }
    
    private void SendSettingsUpdate()
    {
        var json = _settings.ToJsonString();
        ShellPage.SendDefaultIPCMessage(json);
    }
}

```

### Handling IPC in the Runner (C++)

```cpp
// In the runner's message loop
void Runner::HandleIPCMessage(const std::wstring& message)
{
    Json::Value root;
    Json::Reader reader;
    
    if (!reader.parse(message, root))
        return;
        
    std::wstring moduleName = root[L"moduleName"].asString();
    
    if (moduleName == L"MyModule")
    {
        auto& module = modules().at(moduleName);
        module->set_config(root.toStyledString());
    }
}

```

## Summary

- **JSON Persistence**: PowerToys Settings v2 stores all module configurations as JSON files in `%LOCALAPPDATA%\Microsoft\PowerToys\`, accessed through the `SettingsRepository<T>` and `SettingsUtils` classes.
- **Two-Way IPC**: The Settings UI communicates with the runner process via `ShellPage.SendDefaultIPCMessage` using a named pipe, while the runner dispatches messages through `Program.IPCMessageReceivedCallback` and `IPCResponseHandleList`.
- **Module Integration**: Each module implements `set_config` (C++) or `SetConfig` (C#) to receive JSON updates, ensuring type-safe configuration application across the entire PowerToys ecosystem.

## Frequently Asked Questions

### How does PowerToys Settings v2 handle configuration file conflicts?

PowerToys Settings v2 prevents file contention through the `SettingsUtils` class, which manages all JSON read/write operations. When the Settings UI saves changes, it writes to disk immediately, then sends the JSON payload via IPC to the runner. The runner may persist the same configuration through its own `SettingsUtils` instance, ensuring both processes maintain synchronized file states without corruption.

### What is the difference between Settings v1 and Settings v2 in PowerToys?

Settings v1 used a different persistence mechanism and IPC approach, while Settings v2 introduces a standardized JSON-based configuration system with strongly-typed `ISettingsConfig` interfaces. The v2 architecture centralizes settings access through `SettingsRepository<T>`, implements consistent two-way IPC via named pipes, and provides a modern XAML-based UI that communicates through `ShellPage.SendDefaultIPCMessage` rather than the legacy communication methods.

### Can third-party PowerToys modules use the Settings v2 JSON and IPC system?

Yes, third-party modules can integrate with Settings v2 by implementing the `ISettingsConfig` interface for their configuration classes and registering with the `SettingsRepository<T>`. For IPC, modules must handle the `set_config` callback (C++) or `SetConfig` method (C#) to receive JSON updates from the runner, and can send status updates back through the same named pipe infrastructure used by built-in PowerToys modules.

### How does the Settings UI know when a module has successfully applied configuration changes?

The Settings v2 IPC channel supports bidirectional communication, allowing the runner to send confirmation messages or status updates back to the Settings UI. When a module successfully applies configuration changes, the runner can dispatch a JSON message through the same named pipe, which triggers the registered handlers in `IPCResponseHandleList`. These handlers update the view models, which then propagate the confirmation to the XAML bindings, ensuring the UI reflects the actual module state.