# Understanding the PowerToys Update Mechanism and Auto-Update Flow

> Understand the PowerToys update mechanism and auto-update flow. Discover how PowerToys manages updates, from manual checks to automatic background downloads, and how settings control the process.

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

---

**PowerToys coordinates updates between the Settings UI and the Runner process, supporting both manual checks triggered by `GeneralViewModel.CheckForUpdatesClick` and automatic background checks via `PeriodicUpdateWorker` in [`UpdateUtils.cpp`](https://github.com/microsoft/PowerToys/blob/main/UpdateUtils.cpp), with downloads and notifications controlled by Group Policy and metered connection settings.**

The auto-update system in the `microsoft/PowerToys` repository ensures users receive the latest features and security patches without manual intervention. This mechanism relies on a split architecture where the **Settings UI** handles user interactions and the **Runner** manages background update logic. Understanding how these components communicate via IPC and process GitHub release data reveals how PowerToys maintains itself across millions of devices.

## How the PowerToys Update System Works

The update architecture separates concerns between the user-facing **Settings UI** (C#) and the background **Runner** process (C++). The Settings UI captures user input and forwards requests via IPC, while the Runner owns the actual update logic, network requests, and state persistence.

Key components include:

- **[`src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs`](https://github.com/microsoft/PowerToys/blob/main/src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs)** – Handles the "Check for updates" button click.
- **[`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)** – Registers IPC callbacks to bridge UI and Runner.
- **[`src/runner/UpdateUtils.cpp`](https://github.com/microsoft/PowerToys/blob/main/src/runner/UpdateUtils.cpp)** – Contains `CheckForUpdatesCallback`, `PeriodicUpdateWorker`, and `ProcessNewVersionInfo`.
- **[`src/common/updating/updateState.h`](https://github.com/microsoft/PowerToys/blob/main/src/common/updating/updateState.h)** – Defines the `UpdateState` structure persisted across runs.

## Manual Update Checks

When a user clicks **Check for updates** in the Settings UI, the request flows through three distinct layers before reaching GitHub's API.

### Triggering the Check from the UI

In [`GeneralViewModel.cs`](https://github.com/microsoft/PowerToys/blob/main/GeneralViewModel.cs), the `CheckForUpdatesClick` method serializes the request and forwards it via IPC:

```csharp
// GeneralViewModel.cs – manual trigger
private void CheckForUpdatesClick()
{
    SendCheckForUpdatesConfigMSG(customaction.ToString());
}

```

### IPC Transmission to the Runner

The [`ShellPage.xaml.cs`](https://github.com/microsoft/PowerToys/blob/main/ShellPage.xaml.cs) file registers the IPC callback via `SetCheckForUpdatesMessageCallback`, which forwards the UI request to the Runner process. This decouples the UI from the network logic, ensuring the Runner handles all HTTP requests with appropriate system privileges.

### Runner Processing

Upon receiving the IPC message, the Runner invokes `CheckForUpdatesCallback` in [`src/runner/UpdateUtils.cpp`](https://github.com/microsoft/PowerToys/blob/main/src/runner/UpdateUtils.cpp). This function retrieves the current state, queries GitHub for the latest release, and processes the result:

```cpp
// UpdateUtils.cpp – callback entry point
void CheckForUpdatesCallback()
{
    Logger::trace(L"Check for updates callback invoked");
    auto state = UpdateState::read();
    auto new_version_info = std::move(get_github_version_info_async()).get();

    if (!new_version_info)
    {
        state.state = UpdateState::networkError;
        Logger::error(L"Couldn't obtain version info from github: {}", new_version_info.error());
    }
    else
    {
        bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically;
        // GPO may override automatic download
        if (powertoys_gpo::getDisableAutomaticUpdateDownloadValue() == powertoys_gpo::gpo_rule_configured_enabled)
            download_update = false;

        bool updateAvailable = std::holds_alternative<new_version_download_info>(*new_version_info);
        ProcessNewVersionInfo(*new_version_info, state, download_update, false);
    }

    UpdateState::store([&](UpdateState& v) { v = std::move(state); });
}

```

The callback respects **Group Policy Objects (GPO)** via `powertoys_gpo::getDisableAutomaticUpdateDownloadValue` and checks for **metered connections** using `IsMeteredConnection()` before attempting downloads.

## Automatic Background Updates

Beyond manual checks, PowerToys runs a **detached thread** at startup that executes `PeriodicUpdateWorker` in [`UpdateUtils.cpp`](https://github.com/microsoft/PowerToys/blob/main/UpdateUtils.cpp). This worker operates independently of user interaction.

The worker sleeps for `UPDATE_CHECK_INTERVAL_MINUTES` (24 hours by default) between checks. If a check fails, it uses a shorter back-off interval defined by `UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES`.

```cpp
void PeriodicUpdateWorker()
{
    for (;;)
    {
        auto state = UpdateState::read();
        // …calculate sleep interval…
        std::this_thread::sleep_for(std::chrono::minutes{ sleep_minutes_till_next_update });

        // Auto‑download decision
        bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically;
        if (powertoys_gpo::getDisableAutomaticUpdateDownloadValue() == powertoys_gpo::gpo_rule_configured_enabled)
            download_update = false;

        // Retrieve version info from GitHub
        const auto new_version_info = std::move(get_github_version_info_async()).get();
        if (new_version_info.has_value())
        {
            ProcessNewVersionInfo(*new_version_info, state, download_update, true);
            UpdateState::store([&](UpdateState& v){ v = std::move(state); });
        }
        else
        {
            // retry after a short back‑off
            std::this_thread::sleep_for(std::chrono::minutes{ UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES });
        }
    }
}

```

Like the manual flow, the periodic worker respects GPO settings and metered connection status before calling `download_new_version_async`.

## Core Update Processing Logic

The `ProcessNewVersionInfo` function serves as the central decision engine for both manual and automatic flows. It manages the `UpdateState` machine and handles:

- **Recording check timestamps** via `state.githubUpdateLastCheckedDate.emplace(timeutil::now())`
- **Detecting up-to-date status** when `github_version_info` contains `version_up_to_date`
- **Handling new versions** by extracting `new_version_download_info`
- **GPO enforcement** for toast notifications via `powertoys_gpo::getDisableNewUpdateToastValue` and `powertoys_gpo::getSuspendNewUpdateToastValue`
- **Auto-download logic** using `download_new_version_async` when `download_update` is true and the user setting `downloadUpdatesAutomatically` is enabled
- **Toast creation** via `ShowNewVersionAvailable` (which uses the custom URI `powertoys://update_now/`) or `ShowOpenSettingsForUpdate` (using `powertoys://open_overview/`)

When auto-download succeeds, the installer is saved locally and a toast notification offers an **Update now** action. If auto-download is disabled, the toast directs users to the Settings page instead. The final installation is handled by `LaunchPowerToysUpdate`, which executes `PowerToys.Update.exe`.

## UI Integration and State Management

The Settings UI consumes update state through data binding and converters. The `UpdateStateToBoolConverter` in [`src/settings-ui/Settings.UI/Converters/UpdateStateToBoolConverter.cs`](https://github.com/microsoft/PowerToys/blob/main/src/settings-ui/Settings.UI/Converters/UpdateStateToBoolConverter.cs) transforms the persisted `UpdateState` into boolean values that drive UI visibility for update banners and buttons.

State persistence occurs in [`src/common/updating/updateState.h`](https://github.com/microsoft/PowerToys/blob/main/src/common/updating/updateState.h) and [`updateState.cpp`](https://github.com/microsoft/PowerToys/blob/main/updateState.cpp), which provide `UpdateState::read()` and `UpdateState::store()` methods. These ensure update availability survives application restarts, allowing the UI to immediately show update status on launch without re-querying GitHub.

The IPC bridge in [`ShellPage.xaml.cs`](https://github.com/microsoft/PowerToys/blob/main/ShellPage.xaml.cs) registers callbacks via `SetCheckForUpdatesMessageCallback`, creating the communication channel that allows the C# UI to invoke C++ update logic in the Runner process.

## Summary

- PowerToys uses a **split architecture** where the Settings UI handles user input and the Runner manages background update logic in [`UpdateUtils.cpp`](https://github.com/microsoft/PowerToys/blob/main/UpdateUtils.cpp).
- **Manual checks** originate in [`GeneralViewModel.cs`](https://github.com/microsoft/PowerToys/blob/main/GeneralViewModel.cs), travel via IPC through [`ShellPage.xaml.cs`](https://github.com/microsoft/PowerToys/blob/main/ShellPage.xaml.cs), and execute in `CheckForUpdatesCallback`.
- **Automatic checks** run every 24 hours via `PeriodicUpdateWorker`, with shorter retry intervals after failures.
- **GPO settings** and **metered connection** status can disable automatic downloads via `getDisableAutomaticUpdateDownloadValue` and `IsMeteredConnection()`.
- The **UpdateState** machine persists across sessions in [`src/common/updating/updateState.cpp`](https://github.com/microsoft/PowerToys/blob/main/src/common/updating/updateState.cpp), while `UpdateStateToBoolConverter` drives the UI visibility.

## Frequently Asked Questions

### How often does PowerToys check for updates automatically?

The `PeriodicUpdateWorker` in [`src/runner/UpdateUtils.cpp`](https://github.com/microsoft/PowerToys/blob/main/src/runner/UpdateUtils.cpp) sleeps for `UPDATE_CHECK_INTERVAL_MINUTES` (24 hours by default) between checks. If a check fails due to network errors, it uses a shorter back-off period defined by `UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES` before retrying.

### Can I disable automatic updates in PowerToys?

Yes, automatic updates can be disabled through **Group Policy** or the **Settings UI**. The Runner checks `powertoys_gpo::getDisableAutomaticUpdateDownloadValue()` in [`UpdateUtils.cpp`](https://github.com/microsoft/PowerToys/blob/main/UpdateUtils.cpp), which returns `gpo_rule_configured_enabled` when disabled by policy. Additionally, users can toggle automatic downloads in the General settings, though GPO settings override user preferences.

### What happens if I'm on a metered connection?

PowerToys respects Windows metered connection settings via the `IsMeteredConnection()` helper. When on a metered connection, the `download_update` boolean evaluates to `false` in both `CheckForUpdatesCallback` and `PeriodicUpdateWorker`, preventing automatic downloads of the installer. Notifications about available updates may still appear depending on toast settings, but the actual binary will not download until the connection is no longer metered.

### How does the Settings UI know an update is available?

The UI relies on the `UpdateState` persistence layer defined in [`src/common/updating/updateState.h`](https://github.com/microsoft/PowerToys/blob/main/src/common/updating/updateState.h) and [`updateState.cpp`](https://github.com/microsoft/PowerToys/blob/main/updateState.cpp). When the Runner processes a new version via `ProcessNewVersionInfo`, it stores the state using `UpdateState::store()`. The Settings UI reads this state on startup and uses the `UpdateStateToBoolConverter` to transform the raw state into boolean properties that drive visibility of update banners and the "Update now" button.