How the Omarchy Migration System Works: A Complete Guide to Writing Safe Per-User Updates
Omarchy's migration system applies one-time repair scripts per-user when package updates need to modify state that pacman cannot manage directly, storing completion markers in ~/.local/state/omarchy/migrations/ to ensure idempotent execution.
The Omarchy migration system provides a robust mechanism for applying stateful configuration changes across user environments when system package updates require modifications beyond what pacman handles natively. Located in the basecamp/omarchy repository, this per-user workflow ensures that every user individually runs necessary repair scripts while preventing duplicate executions through marker file tracking.
Migration Model and Architecture
All migration scripts reside in the migrations/ directory with the *.sh extension. According to the source code in agents/skills/migrations.md, these scripts are invoked by the public command bin/omarchy-migrate, which executes automatically during the omarchy update process.
The system tracks execution state on a per-user basis. After a migration completes successfully, the migrator creates a marker file at:
~/.local/state/omarchy/migrations/<migration-filename>
This design ensures that every user on the system gets an opportunity to run each migration exactly once, regardless of when they log in or update their environment.
When Migrations Execute
The Omarchy migration system triggers under three specific conditions:
-
During
omarchy update– After package upgrades complete, the update routine automatically runsomarchy-migratefollowed by any post-update hooks. -
At graphical login – The systemd user service
default/systemd/user/omarchy-migrate-notify.servicechecks for pending migrations usingomarchy-migrate --pending. When pending migrations exist, the service displays a notification that opens a terminal and executes the migrator. -
Manually – Users can invoke
omarchy-migrateat any time from their terminal; the system automatically skips previously completed migrations based on marker file presence.
Checking for Pending Migrations
To inspect which migrations are awaiting execution without running them, use the pending flag:
omarchy-migrate --pending
This command lists pending migrations one per line and exits with status 0 when migrations are pending, or a non-zero status otherwise. This interface enables the systemd notification service to determine whether to alert the user at login time.
How to Write a New Migration
Omarchy provides a scaffolding helper to generate properly formatted migration files. Run the following command from the repository root:
omarchy-dev-add-migration --no-edit
This creates a new file named migrations/<unix-timestamp>.sh with the correct permissions and structure.
Required Migration Structure
Every migration script must adhere to strict formatting rules to ensure safe execution:
- Permissions: Set to
0644(readable by all, not executable) - No shebang: The runner explicitly executes scripts with
bash -euo pipefail - Header: Begin with an
echostatement describing the migration's purpose - Idempotency: Every change must first test existing state and exit silently if the work is already done
- Helper commands: Use Omarchy helpers such as
omarchy-cmd-presentandomarchy-pkg-addfor common tasks - No shell restarts: Do not restart the Omarchy shell within migrations; the update flow handles shell reloading automatically after migrations complete
Minimal Migration Example
The following example from agents/skills/migrations.md demonstrates a safe, idempotent migration that relinks a Neovim theme:
# Example migration: Relink Neovim theme to the current Omarchy state
echo "Relink Neovim theme to Omarchy current state"
theme_link="$HOME/.config/nvim/lua/plugins/theme.lua"
target="../../../../.local/state/omarchy/current/theme/neovim.lua"
# If the symlink does not exist, nothing to fix
[[ -L $theme_link ]] || exit 0
# Re-create a correct relative symlink
ln -sfn "$target" "$theme_link"
This pattern checks for the existence of the target state before making changes, ensuring the script can run multiple times without error.
Testing Your Migration
Validate migrations against a temporary home directory to avoid affecting your real user environment:
HOME=$(mktemp -d) bash -euo pipefail migrations/1781158082.sh
To re-run a migration after fixing a bug, remove its marker file and invoke the migrator:
rm ~/.local/state/omarchy/migrations/1781158082.sh
omarchy-migrate
Summary
- Omarchy migrations live in
migrations/*.shand execute viabin/omarchy-migratewhen users run updates or log in graphically. - The system tracks completion per-user via marker files in
~/.local/state/omarchy/migrations/, preventing duplicate executions. - Use
omarchy-dev-add-migration --no-editto scaffold new migrations with proper0644permissions and no shebang. - All migrations must be idempotent, testing state before modification and exiting silently when no work is required.
- Test migrations in temporary directories and avoid restarting the Omarchy shell within migration scripts.
Frequently Asked Questions
Where does Omarchy store migration completion state?
Omarchy stores per-user completion markers in ~/.local/state/omarchy/migrations/<migration-filename>. Each user on the system maintains their own independent state, ensuring that migrations run once per user rather than system-wide. The omarchy-migrate command checks for these marker files before executing any migration script.
Can I run a single migration manually without affecting others?
Yes. When you run omarchy-migrate, it automatically skips any migrations that have already created their marker files in your home directory. To force a specific migration to re-run, delete its corresponding marker file from ~/.local/state/omarchy/migrations/ and execute omarchy-migrate again.
What permission mode should migration scripts have?
Migration scripts must have permissions set to 0644. They should not be executable because the omarchy-migrate runner explicitly sources them with bash -euo pipefail rather than executing them directly. This ensures consistent error handling and pipe failure detection across all migrations.
How does Omarchy notify users about pending migrations at login?
The systemd user service omarchy-migrate-notify.service runs at graphical login and executes omarchy-migrate --pending. If the command returns exit code 0 (indicating pending migrations exist), the service displays a desktop notification that opens a terminal and runs the migrator when clicked. This ensures users do not miss critical configuration updates required for their environment to function correctly.
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 →