Files
omarchycn/docs/migrations.md
T
David Heinemeier HanssonandClaude Fable 5 c992cdff10 Restart the shell unconditionally after every update
Updates routinely replace the shell's QML, and a stale process can
lazy-load new files into old code. Restarting at the end of every
omarchy update removes the need for migrations to restart the shell
or defer one with the restart-shell-required marker: the login-time
migration path already runs a fresh shell that hot-reloads shell.json.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 16:52:02 -05:00

4.3 KiB

Omarchy migrations

Omarchy migrations are one-time repair scripts for existing installs. They are used when a package update needs to change state that pacman cannot safely own by itself.

Migration model

Migrations live in:

migrations/*.sh

They run as the current Omarchy user through omarchy-migrate, normally during omarchy update. A migration may touch user/session state (~/.config, ~/.local, user systemd, browser/editor prefs, DBus/session state), and may also perform machine-wide repairs when needed.

Completion state is per-user:

~/.local/state/omarchy/migrations/<migration filename>

That means every user gets a chance to run every migration. Migrations run as the user; privileged operations should invoke the appropriate helper or privilege prompt themselves. Migrations must be idempotent: if one user already applied a machine-wide repair, the same migration running for another user should detect that and no-op.

When migrations run

During omarchy update

omarchy update is the normal update path. It runs package updates, then:

omarchy-migrate
omarchy-hook post-update

omarchy-migrate waits for any active pacman transaction to finish, then runs all pending migrations for the current user in the visible update terminal.

At login

Every graphical login starts omarchy-migrate-notify.service after graphical-session.target. The notifier checks:

omarchy-migrate --pending

It stays silent while omarchy update holds its lock, since that update applies the pending migrations itself.

If that user has pending migrations, it shows a notification that opens a terminal for:

omarchy-migrate

The notifier never runs migrations silently in the background.

This is what covers users who did not run the update themselves: someone who bypassed the pacman guard with sudo env OMARCHY_ALLOW_DIRECT_PACMAN=1 pacman -Syu, and any second user on the machine, whose migration markers are per-user and therefore still missing after another user updated.

Login is the only trigger on purpose. Watching the packaged migration directory also fires during a normal omarchy update, which prompts for migrations that omarchy-migrate is about to run in the visible update terminal.

Manually

Users can safely run:

omarchy-migrate

at any time. Already-completed migrations are skipped.

Inspecting pending migrations

Use:

omarchy-migrate --pending

Exit behavior:

  • 0 — one or more migrations are pending
  • non-zero — no migrations are pending

Output is one pending migration per line:

1781158082.sh

Creating a migration

Use the helper:

omarchy-dev-add-migration --no-edit

This creates:

migrations/<unix timestamp>.sh

New migration format:

  • File permissions must be 0644 (-rw-r--r--). Migration runners execute them with bash -euo pipefail, not through executable bits.
  • No shebang line.
  • Start with an echo describing what the migration does.
  • Use $OMARCHY_PATH to reference the Omarchy directory.
  • Be idempotent. Check existing state before changing it.
  • Use helper commands such as omarchy-cmd-present, omarchy-cmd-missing, omarchy-pkg-add, omarchy-pkg-drop, omarchy-pkg-present, and omarchy-pkg-missing when appropriate.
  • Never restart the Omarchy shell. omarchy update restarts it unconditionally after migrations run, and the login-time shell already runs current code and hot-reloads shell.json edits.

Example:

echo "Relink Neovim theme to Omarchy current state"

theme_link="$HOME/.config/nvim/lua/plugins/theme.lua"
current_relative_target="../../../../.local/state/omarchy/current/theme/neovim.lua"

[[ -L $theme_link ]] || exit 0
ln -sfn "$current_relative_target" "$theme_link"

Testing migrations

Run a migration against a temporary home when possible:

HOME=$(mktemp -d) bash -euo pipefail migrations/<timestamp>.sh

To rerun a migration locally, remove its marker and run the migrator:

rm ~/.local/state/omarchy/migrations/<migration>.sh
omarchy-migrate

Omarchy 4.0 is upgraded through bin/omarchy-upgrade-to-quattro, not through the normal migration runner. Do not add compatibility migrations for old installer layouts; put pre-4 package-layout transition work in the upgrade command instead.