How Magisk Handles Module Upgrades and the Update Mechanism

Magisk handles module upgrades by comparing versionCode values in module.prop, downloading updates via the updateCheck URL, and reinstalling through the install_module function while touching an update flag file to signal the Magisk app.

The topjohnwu/Magisk repository implements a robust, file-based upgrade system for Magisk modules that ensures safe updates without breaking existing installations. This mechanism relies on specific metadata files, shell-based installation scripts, and flag files to coordinate between the core Magisk framework and the companion Android app.

Understanding the Magisk Module Structure

Every Magisk module is a standard ZIP package containing a module.prop file at its root. This properties file defines the module's identity and upgrade behavior through several key fields:

  • id – A unique identifier used as the directory name under /data/adb/modules/
  • version – Human-readable version string
  • versionCode – Integer used for deterministic version comparison
  • updateCheck – Optional URL endpoint for fetching update metadata

When a module is installed, Magisk extracts this metadata to /data/adb/modules/<id>/module.prop, creating a persistent record that the upgrade mechanism references during version checks.

The Magisk Module Upgrade Workflow

The upgrade process follows a deterministic sequence that ensures atomic replacement of module files while preserving the module's identity and state.

Version Comparison and Detection

The Magisk app initiates upgrades by reading the installed /data/adb/modules/<id>/module.prop. It compares the local versionCode against the remote version available through the updateCheck URL or user-provided ZIP. If the remote versionCode is higher, the app marks the module as having an available upgrade.

Fetching Updates via updateCheck

Modules that declare an updateCheck URL in their module.prop enable automatic update detection. The Magisk app contacts this endpoint to retrieve update metadata or the newer ZIP file directly, storing the download temporarily before triggering the installation process.

The Re-installation Process

Magisk performs upgrades by re-running the install_module function defined in scripts/util_functions.sh. Because the module's id remains unchanged, the installer:

  1. Removes the existing directory at /data/adb/modules/<id>
  2. Extracts and writes the new module files to the same location
  3. Preserves module state files if necessary

This atomic replacement ensures no orphaned files remain from previous versions.

Signaling Upgrade Completion with the Update Flag

After a successful reinstall, the installer creates an empty file named update inside the module directory to signal the Magisk app. The relevant code in scripts/util_functions.sh handles this:


# scripts/util_functions.sh – install_module()

if $BOOTMODE; then
    # Update info for Magisk app

    mktouch /data/adb/modules/$MODID/update
fi

This flag file at /data/adb/modules/<id>/update persists until the Magisk app reads it and updates its UI, typically displaying an "Updated" badge or refreshing the module list to reflect the new version.

Manual Module Upgrades via CLI

Users can trigger upgrades manually without the Magisk app by using the command-line interface. The following command invokes the same install_module function used by the GUI:


# Download the newer module zip to device storage

# Then run the installer in boot mode

magisk --install-module /sdcard/NewMod.zip

This execution flow:

  • Extracts module.prop to identify the module ID
  • Removes the old installation at /data/adb/modules/<id>
  • Copies new files and touches the update flag
  • Cleans up temporary files upon completion

Post-Upgrade Hooks and Cleanup

After the core upgrade completes, Magisk executes several hook scripts that allow modules to perform migration tasks or restart services:

  • customize.sh – Runs during installation to handle custom extraction logic or version-specific migrations
  • post-fs-data.sh – Executes after the kernel mounts filesystems but before Zygote starts, allowing modules to adjust permissions or prepare data directories
  • service.sh – Runs late in the boot process when the system is fully operational, suitable for restarting daemons or applying runtime patches

The installer also cleans up stale state files such as remove or disable flags during the upgrade process, ensuring the module starts fresh with the new version while maintaining its enabled/disabled status as appropriate.

Key Source Files Implementing Module Upgrades

The upgrade mechanism spans both native shell scripts and Java components within the Magisk codebase:

File Role
scripts/util_functions.sh – install_module() Core installer function that handles both fresh installs and upgrades; creates the update flag file.
app/shared/src/main/java/com/topjohnwu/magisk/StubApk.java Provides update(Context) helper for app-side update coordination.
app/stub/src/main/java/com/topjohnwu/magisk/DummyProvider.java Content provider stub that queries module state, including detection of the update flag file.
docs/details.md Documents the upgrade flag behavior and UI expectations for module developers.

Summary

  • Magisk modules are upgraded by reinstalling the ZIP package while preserving the module ID, ensuring atomic replacement of files.
  • The install_module function in scripts/util_functions.sh handles both initial installations and upgrades, removing old files at /data/adb/modules/<id> before extracting new content.
  • An empty update flag file is created at /data/adb/modules/<id>/update to signal the Magisk app that an upgrade occurred.
  • Modules declare update endpoints via the updateCheck field in module.prop, enabling automatic version detection by comparing versionCode values.
  • Post-upgrade hooks including customize.sh, post-fs-data.sh, and service.sh allow modules to execute migration logic and restart services.

Frequently Asked Questions

How does Magisk detect available module updates?

The Magisk app reads the installed module.prop from /data/adb/modules/<id>/module.prop and compares the local versionCode against the remote version fetched from the module's declared updateCheck URL. If the remote versionCode is higher, the app marks the module as having an update available.

What happens to old module files during an upgrade?

During an upgrade, the install_module function in scripts/util_functions.sh completely removes the existing directory at /data/adb/modules/<id> before extracting the new module files. This ensures no stale files remain from previous versions while preserving the module's identity through its consistent ID.

Can I upgrade Magisk modules without using the official app?

Yes, you can trigger manual upgrades via the command line using magisk --install-module /path/to/NewMod.zip. This command invokes the same install_module function used by the GUI, performing the version comparison, atomic replacement, and creation of the update flag file without requiring the Magisk app interface.

What is the purpose of the update flag file in Magisk modules?

The empty file located at /data/adb/modules/<id>/update serves as a persistent signal to the Magisk app that the module has just been upgraded. The app scans for this flag during startup to display "Updated" badges in the UI and trigger any necessary post-install hooks defined in the module's scripts.

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 →