How Modly Handles Extension Backup Creation During Upgrades

Modly safeguards existing extensions during upgrades by atomically renaming the current installation to a timestamped backup directory before swapping in the new version, ensuring a reliable rollback path if the installation fails.

Modly is an Electron-based extension manager that prioritizes data safety during updates. When upgrading extensions, the application implements a robust backup strategy that prevents data loss and enables automatic recovery. This article examines how the lightningpixel/modly repository handles extension backup creation during upgrades through atomic file operations and staged deployments.

The Staging Phase – Preparing for Safe Extension Upgrades

Before modifying any existing extension files, Modly prepares a staging environment to isolate the new version. The installer first copies the extracted extension into a temporary staging folder named .modly-staging-<id>-<timestamp>.

To detect interrupted installations, Modly writes an incomplete marker file (.modly-incomplete) into the staging directory:

// Marker indicates installation is in progress
const incompleteMarker = join(stagingDir, EXT_INCOMPLETE_MARKER);
await writeFile(incompleteMarker, '');

This marker serves as a crash detection mechanism. If the application terminates unexpectedly, the startup reconciler can identify incomplete installations and trigger recovery procedures on the next launch.

Atomic Backup Creation During Extension Upgrades

The actual backup creation occurs in electron/main/ipc-handlers.ts using helper functions from electron/main/extension-path-guard.ts. When an upgrade begins, Modly checks if the destination directory already exists:

const destDir = resolveExtensionPathWithinRoot(extensionsDir, extensionId);
const backupDir = existsSync(destDir)
    ? buildExtensionBackupPath(extensionsDir, extensionId, String(Date.now()))
    : null;

The buildExtensionBackupPath function (defined in extension-path-guard.ts) constructs the backup path using a strict naming convention:

// From electron/main/extension-path-guard.ts
export const EXT_BACKUP_PREFIX = '.modly-backup-';

export function buildExtensionBackupPath(
  rootDir: string,
  extensionId: unknown,
  suffix: string,
): string {
  const safeId = assertSafeExtensionId(extensionId);
  return resolvePathWithinRoot(rootDir, `${EXT_BACKUP_PREFIX}${safeId}-${suffix}`);
}

This generates paths like .modly-backup-<extensionId>-<timestamp>, ensuring each backup is unique and timestamped. If the destination exists, Modly performs an atomic rename to move the current version to the backup location:

if (backupDir) {
  const parked = await renameWithRetry(destDir, backupDir, 'ext-install');
  if (!parked.ok) {
    // Abort installation – extension directory is locked
    throw new Error(`Cannot create backup: ${parked.error}`);
  }
}

The renameWithRetry utility handles transient file system locks and provides clear error messages when folders cannot be moved.

Swapping and Activation Process

After securing the backup, Modly atomically promotes the staged version to the active extension directory:

const activated = await renameWithRetry(stagingDir, destDir, 'ext-install');

This two-step rename sequence—first moving the old version to backup, then moving the new version to production—ensures that the destDir always contains a valid extension state, even if the process crashes between operations.

Cleanup and Automatic Restoration

Once the new extension is successfully activated, Modly performs cleanup operations:

// Remove the incomplete marker to signal success
const markerGone = await rmWithRetry(join(destDir, EXT_INCOMPLETE_MARKER), 'ext-install');

// Delete the backup only after confirming successful installation
if (backupDir && markerGone.ok) {
  void rmWithRetry(backupDir, 'ext-install');
}

If the installation fails at any point, Modly executes the inverse operation: it removes the partially-installed staging directory and restores the backup by renaming it back to destDir. The backup may also be restored automatically by the startup reconciler if a previous crash left an incomplete marker behind.

Summary

  • Staging with crash detection: Modly writes new extensions to temporary staging directories with .modly-incomplete markers to detect interrupted installations.
  • Timestamped backups: The buildExtensionBackupPath function creates unique backup directories using the .modly-backup-<id>-<timestamp> naming pattern.
  • Atomic operations: All critical file moves use renameWithRetry to ensure atomicity and handle file system locks gracefully.
  • Automatic recovery: Backups are restored automatically if upgrades fail or if the application crashes during installation.
  • Cleanup on success: Backup directories are deleted only after the incomplete marker is successfully removed, confirming a healthy installation.

Frequently Asked Questions

How does Modly name extension backup directories?

Modly uses the buildExtensionBackupPath function in electron/main/extension-path-guard.ts to generate backup names with the pattern .modly-backup-<extensionId>-<timestamp>. This ensures each backup is unique and traceable to a specific point in time.

What happens if a Modly extension upgrade is interrupted?

If an upgrade is interrupted, the .modly-incomplete marker remains in the staging directory. On the next application launch, the startup reconciler detects this marker and automatically restores the previous version from the backup directory, rolling back any partial changes.

Where is the extension backup logic implemented in Modly?

The core backup logic resides in electron/main/ipc-handlers.ts, which orchestrates the upgrade flow. Helper functions for path construction and safety checks are defined in electron/main/extension-path-guard.ts, including buildExtensionBackupPath and the EXT_BACKUP_PREFIX constant.

Does Modly keep backups after successful extension upgrades?

No. Modly deletes the backup directory immediately after confirming the new extension installed correctly—that is, after successfully removing the .modly-incomplete marker. This prevents accumulation of outdated extension versions while ensuring the backup persists only as long as needed for recovery.

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 →