How Zed Handles Auto-Updates Across macOS, Linux, and Windows
Zed implements a unified auto-update system using three specialized crates—auto_update, auto_update_helper, and auto_update_ui—that poll the Zed Cloud for new releases, download platform-specific assets, and install them using OS-native tools like rsync on Unix or a helper process on Windows.
The Zed editor's auto-update mechanism is designed to deliver seamless, cross-platform updates while respecting the constraints of each operating system. According to the zed-industries/zed source code, the system abstracts platform differences behind a common polling and download layer, delegating only the final installation step to OS-specific implementations.
Core Architecture of Zed's Auto-Update System
Zed's update logic is partitioned into three distinct crates to maintain separation of concerns:
auto_update– Contains the core logic incrates/auto_update/src/auto_update.rs. It manages theAutoUpdaterentity, handles polling intervals, version comparison, asset downloading, and delegates installation to platform-specific functions.auto_update_helper– A Windows-only helper crate located incrates/auto_update_helper. It provides thefinalize_auto_update_on_quitfunction that runs after the main Zed process exits to replace the running executable, since Windows locks files during execution.auto_update_ui– Located incrates/auto_update_ui/src/auto_update_ui.rs, this crate renders notification toasts when updates complete and provides the "View Release Notes" action.
The Auto-Update Lifecycle
Initialization and Polling
When Zed launches, auto_update::init creates a global AutoUpdater instance and starts a background polling loop if AutoUpdateSetting is enabled (default: true):
pub fn init(client: Arc<Client>, cx: &mut App) {
let updater = AutoUpdater::new(version, client, cx);
cx.set_global(GlobalAutoUpdate(Some(updater)));
if AutoUpdateSetting::get_global(cx).0 {
updater.start_polling(cx);
}
}
Source: crates/auto_update/src/auto_update.rs:71-85
The start_polling method spawns an async task that calls poll(UpdateCheckType::Automatic) every hour (POLL_INTERVAL), sleeping between checks using the background executor.
Version Detection and Comparison
The poll method triggers AutoUpdater::update, which queries the Zed Cloud for the latest release asset. The version comparison logic differs by release channel:
- Stable/Preview – Uses semantic versioning comparison (
fetched_version > installed_version). - Nightly – Compares build metadata (Git SHA) against the installed binary's SHA or cached value.
If check_if_fetched_version_is_newer determines the fetched version is newer, the updater transitions to the Downloading state.
Downloading Release Assets
download_release streams the platform-specific asset (DMG for macOS, tar.gz for Linux, EXE for Windows) into a temporary file:
async fn download_release(
target_path: &Path,
release: ReleaseAsset,
client: Arc<HttpClientWithUrl>
) -> Result<()> {
let mut target_file = File::create(&target_path).await?;
let mut response = client.get(&release.url, Default::default(), true).await?;
smol::io::copy(response.body_mut(), &mut target_file).await?;
Ok(())
}
Source: crates/auto_update/src/auto_update.rs:72-86
The temporary location is determined by InstallerDir::new(), which returns a tempfile::tempdir() on Unix systems and an updates folder adjacent to the executable on Windows.
Platform-Specific Installation
After downloading, install_release dispatches to OS-specific implementations:
macOS – install_release_macos mounts the DMG using hdiutil, rsyncs the Zed.app bundle to the Applications folder (or original location), and uses a MacOsUnmounter RAII guard to ensure the disk image is detached.
Linux – install_release_linux extracts the tarball with tar -xzf, then uses rsync to copy the new zed.app bundle into ~/.local or the original installation directory.
Windows – install_release_windows executes the downloaded installer with /verysilent /update=true flags. Since Windows prevents overwriting a running executable, the installer writes a flag file (versions.txt) and spawns auto_update_helper.exe. The helper's finalize_auto_update_on_quit function waits for the main Zed process to exit, then replaces the binary and relaunches Zed.
Sources:
- macOS:
crates/auto_update/src/auto_update.rs:58-86 - Linux:
crates/auto_update/src/auto_update.rs:44-55 - Windows:
crates/auto_update/src/auto_update.rs:46-51andcrates/auto_update_helper/src/updater.rs:46-68
Restart and Finalization
Once installation completes, the updater signals the application to restart:
if let Some(new_binary_path) = new_binary_path {
cx.update(|cx| cx.set_restart_path(new_binary_path));
}
Source: crates/auto_update/src/auto_update.rs:46-49
On macOS and Linux, the restart occurs immediately. On Windows, the restart is delegated to the helper process, which reads the update flag and handles the relaunch after the main process terminates.
User Interface Integration
When an update completes, auto_update_ui::notify_if_app_was_updated displays a notification toast. It checks a KV-store flag (auto-updater-should-show-updated-notification) set by the updater:
if let Some(content) = announcement_for_version(&version) {
// Custom "What's new" announcement
} else {
// Standard "Updated to <channel> <version>" with release notes button
}
Source: crates/auto_update_ui/src/auto_update_ui.rs:53-115
The UI also provides the ViewReleaseNotesLocally action, which fetches release notes from the Zed Cloud and opens them in an editor tab.
Summary
- Zed's auto-update system is implemented across three crates:
auto_update(core logic),auto_update_helper(Windows finalization), andauto_update_ui(notifications). - Polling mechanism checks the Zed Cloud every hour via
AutoUpdater::poll, comparing semantic versions (Stable/Preview) or Git SHAs (Nightly). - Platform-specific installation uses
rsyncandhdiutilon macOS,tarandrsyncon Linux, and a helper process on Windows to overcome file locking limitations. - Restart coordination happens immediately on Unix systems, while Windows delegates to
finalize_auto_update_on_quitin the helper crate to swap binaries after the main process exits. - UI notifications are handled by
auto_update_ui, showing toasts whennotify_if_app_was_updateddetects the update flag in the KV store.
Frequently Asked Questions
How does Zed handle auto-updates on Windows differently from macOS and Linux?
Windows prevents overwriting a running executable, so Zed uses a two-stage process. The main application downloads the update and spawns auto_update_helper.exe, which waits for the main process to exit. The helper's finalize_auto_update_on_quit function then replaces the binary and relaunches Zed. On macOS and Linux, the updater uses rsync to directly overwrite the application bundle while running, then triggers an immediate restart via cx.set_restart_path.
What triggers Zed to check for updates automatically?
When Zed initializes, auto_update::init creates a global AutoUpdater instance. If AutoUpdateSetting is enabled (default: true), the system calls start_polling, which spawns an async loop that executes poll(UpdateCheckType::Automatic) every hour (POLL_INTERVAL). Users can also trigger manual checks via the Check action, which forces an immediate poll regardless of the timer.
How does Zed determine if a downloaded version is newer than the installed version?
The comparison logic in check_if_fetched_version_is_newer differs by release channel. For Stable and Preview channels, Zed performs a standard semantic version comparison where a higher version number indicates a newer release. For the Nightly channel, Zed compares the Git SHA build metadata from the fetched release against the installed binary's SHA or a cached value from the previous update, ensuring nightly builds update to the latest commit.
Where does Zed download updates before installing them?
Zed streams release assets into temporary directories created by InstallerDir::new(). On macOS and Linux, this returns a tempfile::tempdir() that persists for the duration of the installation process. On Windows, the downloaded installer executable is placed in an updates folder adjacent to the running Zed.exe. After successful installation, these temporary files are cleaned up, with the Windows helper process handling final cleanup after the binary swap completes.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →