# How Omarchy Migrations Work: A Complete Guide to System Updates

> Learn how Omarchy migrations work with this guide. Discover how per-user shell scripts update your system state safely via marker files and the omarchy-migrate command.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: how-to-guide
- Published: 2026-09-01

---

**Omarchy migrations are per-user shell scripts that perform one-time repairs or adjustments when package updates cannot safely modify system state, tracked via marker files in `~/.local/state/omarchy/migrations/` and executed through the `omarchy-migrate` command.**

When you update the Omarchy declarative desktop environment, some changes require more than just package replacement—they need intelligent, context-aware fixes to user configurations or shared system state. This article explains how Omarchy's migration system bridges that gap, based on the implementation in the `omacom/omarchy` repository.

## Where Migrations Live and How They're Tracked

All migration scripts reside in the `migrations/` directory as `*.sh` files (`migrations/*.sh`). These are small, focused Bash scripts designed for atomic, one-time execution.

Each migration completes **per-user**, not globally. After a migration runs, `omarchy-migrate` creates a marker file in:

```bash
~/.local/state/omarchy/migrations/<migration-filename>

```

This design ensures every user account on a machine independently runs each migration. On subsequent executions, `omarchy-migrate` skips any migrations where this marker already exists. This per-user isolation prevents partial system states and ensures multi-user machines remain consistent.

## When Omarchy Migrations Run

The migration system triggers through four distinct paths:

### During `omarchy update`

The primary trigger occurs automatically after package updates. The `omarchy update` command executes this sequence:

1. Update packages
2. Run `omarchy-migrate`
3. Run post-update hook (`omarchy-hook post-update`)

The `omarchy-migrate` command waits for any active `pacman` transaction to complete, then executes all pending migrations for the current user directly in the visible update terminal. You see the output in real-time.

### At Graphical Login

Each graphical login starts the systemd user service at `default/systemd/user/omarchy-migrate-notify.service`. This service calls `omarchy-migrate --pending`. If pending migrations exist, it displays a desktop notification that, when clicked, opens a terminal and runs `omarchy-migrate`.

**Critical safety note:** This notification system never runs migrations automatically in the background. The user must explicitly open a terminal and execute the command.

### Manual Execution

Users can run migrations anytime:

```bash

# Execute all pending migrations for current user

omarchy-migrate

```

The command scans `migrations/`, skips completed migrations (those with marker files), and runs the remainder.

### Inspecting Pending Migrations

Check what needs to run without executing:

```bash
omarchy-migrate --pending

```

This prints pending migrations to stdout and exits with status `0` when migrations exist, non-zero otherwise—useful for scripting and the login notifier service.

## Core Design Principles

### Idempotency

Migrations **must be safe to re-run**. If a machine-wide repair was already applied by another user, the script should detect this condition and no-op gracefully. The migration guide in the repository documentation emphasizes this requirement.

### User-Context Execution

Migrations run as the current user, never as root. Any privileged operations must explicitly invoke appropriate helpers or request elevation. This limits blast radius and follows least-privilege principles.

### Explicit User Action for Notifications

The `omarchy-migrate-notify.service` only prompts—it never auto-runs. Users retain full control over when migrations execute.

## Examining Migration Files

### Example Migration Structure

A typical migration script follows this pattern:

```bash
#!/usr/bin/env bash

# 1788009111.sh – Rename deprecated config directory

if [[ -d "$HOME/.omarchy-old" ]]; then
    mv "$HOME/.omarchy-old" "$HOME/.omarchy-backup-$(date +%s)"
    echo "Migrated old config to backup"
fi

# Completion marker handled automatically by omarchy-migrate

```

The numeric prefix (`1788009111`) appears to use a timestamp or sequence number for ordering, though the system executes all pending migrations regardless of order.

### Triggering Login Notifications Manually

For debugging or testing:

```bash
systemctl --user start omarchy-migrate-notify.service

```

## Key Files and Their Roles

| File | Purpose |
|------|---------|
| [`agents/skills/migrations.md`](https://github.com/omacom/omarchy/blob/main/agents/skills/migrations.md) | Complete migration model documentation, execution triggers, and authoring guidelines |
| `migrations/*.sh` | Actual migration scripts shipped with each Omarchy release |
| `bin/omarchy-migrate` | Public command that scans and executes pending per-user migrations |
| `bin/omarchy-migrate-notify` | Helper script invoked by systemd to display login-time notifications |
| `default/systemd/user/omarchy-migrate-notify.service` | Systemd user unit triggering notifications after graphical login |
| [`docs/update-process.md`](https://github.com/omacom/omarchy/blob/main/docs/update-process.md) | Full update pipeline documentation including migration phase |
| [`docs/file-layout.md`](https://github.com/omacom/omarchy/blob/main/docs/file-layout.md) | Directory structure reference for migrations and state markers |

## Summary

- **Omarchy migrations** are per-user shell scripts in `migrations/*.sh` that perform one-time repairs package managers cannot handle
- **Completion tracking** uses marker files in `~/.local/state/omarchy/migrations/` per user
- **Three execution triggers**: during `omarchy update`, at graphical login (via notification), or manual `omarchy-migrate` invocation
- **Safety constraints**: idempotent design, user-context execution, explicit user consent for login-triggered runs
- **Core commands**: `omarchy-migrate` (run pending), `omarchy-migrate --pending` (list only)

## Frequently Asked Questions

### Why do migrations run per-user instead of system-wide?

Each user may have different configuration states requiring different repairs. The marker file system in `~/.local/state/omarchy/migrations/` ensures personalized handling without assuming homogeneous environments across accounts.

### What happens if a migration fails partway through?

Run `omarchy-migrate` again—migrations are designed to be idempotent. They should detect partial completion and resume or complete safely. Check the terminal output from `omarchy update` or manual execution for specific error details.

### Can I skip a migration I don't want to run?

The system does not provide a native skip mechanism. However, you can manually create the marker file that `omarchy-migrate` checks: `touch ~/.local/state/omarchy/migrations/<script-name>`. Only do this if you fully understand what the migration does and have applied equivalent changes manually.

### How do I know if pending migrations exist before logging in graphically?

Run `omarchy-migrate --pending` from any terminal session. Exit status `0` indicates pending migrations exist; non-zero means you're fully caught up.