# How Omarchy Migrations Are Stored and Executed: Complete Technical Guide

> Learn how Omarchy migrations store and execute configuration changes as timestamped shell scripts. This technical guide explains the process and tracking mechanisms.

- Repository: [37signals/omarchy](https://github.com/basecamp/omarchy)
- Tags: deep-dive
- Published: 2026-08-27

---

**Omarchy treats configuration changes as versioned migrations, storing each as a timestamped shell script in `migrations/` and executing them via the `omarchy-migrate` command while tracking completion through marker files in the user's state directory.**

Omarchy, the opinionated Linux workstation system developed by Basecamp, manages system evolution through a deterministic migration framework. Understanding how Omarchy migrations are stored and executed is essential for contributors and power users who need to track configuration drift or implement custom system modifications. The system employs Unix-epoch timestamp naming and POSIX-compliant shell scripts to ensure idempotent, safely ordered upgrades across all installations.

## Migration Storage Architecture

### Timestamped Shell Scripts in the Migrations Directory

Every migration in Omarchy lives as a standalone, POSIX-compatible shell script within the repository’s `migrations/` directory. Files are named using Unix-epoch timestamps—such as [`1787618700.sh`](https://github.com/basecamp/omarchy/blob/main/1787618700.sh) and [`1787494718.sh`](https://github.com/basecamp/omarchy/blob/main/1787494718.sh)—which ensures that lexical filesystem order matches chronological execution order. This design removes the need for complex dependency resolution while guaranteeing that migrations apply in the exact sequence they were introduced to the codebase.

### User-State Marker Files

The system tracks which migrations have already run by creating empty marker files in the user’s state directory, specifically `$HOME/.local/state/omarchy/migrations/`. When `bin/omarchy-migrate` executes, it compares the filenames in the source `migrations/` directory against these markers to determine which scripts are pending. This approach provides true idempotence; once a migration completes successfully, its corresponding marker prevents re-execution during subsequent runs.

## The Migration Execution Pipeline

### Discovery and Ordering via omarchy-migrate

The public command **`omarchy-migrate`** (located at `bin/omarchy-migrate`) drives the entire migration process. First, it scans `$OMARCHY_PATH/migrations/*.sh` (defaulting to `/usr/share/omarchy/migrations`) and sorts the filenames to establish execution order. The tool then checks for corresponding marker files in the user's state directory to filter out completed migrations, as demonstrated in the test suite at [`test/shell.d/migrate-wrapper-test.sh`](https://github.com/basecamp/omarchy/blob/main/test/shell.d/migrate-wrapper-test.sh).

### Safe Execution with Bash Strict Mode

Pending migrations execute under `bash -euo pipefail`, which causes immediate termination if any command exits with a non-zero status, if an undefined variable is referenced, or if a pipeline fails. This strict error handling prevents partial state application—if a migration fails, the runner aborts immediately without creating a marker file, leaving the migration in an unmarked state for retry after the issue is resolved.

### Automatic Marker Creation

Upon successful completion (exit 0), the runner automatically creates a marker file in `$HOME/.local/state/omarchy/migrations/` matching the script's basename. The migration script itself does not handle this marking; the runner assumes responsibility for state tracking, ensuring consistency across all migration types regardless of their internal implementation.

## Desktop Notification Integration

### Systemd User Service for Pending Migrations

To ensure users never miss pending configuration updates, Omarchy includes a notification system triggered by the `omarchy-migrate-notify.service` systemd user unit. Defined in `default/systemd/user/omarchy-migrate-notify.service`, this service runs on every login and invokes the `omarchy-migrate-notify` helper binary. This binary internally executes `omarchy-migrate --pending` to check for work, displaying a desktop toast with the title "Pending Omarchy Migrations" only when unapplied scripts exist, as documented in [`docs/notifications.md`](https://github.com/basecamp/omarchy/blob/main/docs/notifications.md).

## Working with Omarchy Migrations

### Running and Checking Migration Status

Use the following commands to manage migrations:

```bash

# Execute all pending migrations for the current user

omarchy-migrate

# List pending migrations without executing them

omarchy-migrate --pending

```

### Creating Custom Migrations

Developers can add personal migrations by creating timestamped scripts in the appropriate directory:

```bash

# Create a new migration with current timestamp

cat >"$HOME/.local/share/omarchy/migrations/$(date +%s).sh" <<'SH'
#!/usr/bin/env bash

# Example migration: enable a new default config

install_default_config "myfeature.conf"
SH
chmod +x "$HOME/.local/share/omarchy/migrations/$(date +%s).sh"

```

The next invocation of `omarchy-migrate` will automatically detect and execute this script.

## Summary

- Omarchy migrations are stored as **Unix-epoch timestamped shell scripts** in the `migrations/` directory, ensuring lexical order equals chronological order.
- The **`omarchy-migrate`** command handles discovery, execution with `bash -euo pipefail`, and automatic marker file creation in `$HOME/.local/state/omarchy/migrations/`.
- **Idempotence** is guaranteed through marker files; successfully completed migrations are never re-run.
- **Safety mechanisms** include strict error handling that aborts on first failure, preventing partial system states.
- **User notifications** occur via the `omarchy-migrate-notify.service` systemd unit, which alerts users to pending work at login.

## Frequently Asked Questions

### Where are Omarchy migration files stored?

Migration source files reside in the repository's `migrations/` directory (typically `/usr/share/omarchy/migrations/` on installed systems), while completion markers indicating which migrations have run are stored in the user's state directory at `$HOME/.local/state/omarchy/migrations/`.

### How does Omarchy ensure migrations run in the correct order?

Omarchy names migration files using Unix-epoch timestamps (e.g., [`1787618700.sh`](https://github.com/basecamp/omarchy/blob/main/1787618700.sh)). Since filesystems sort these numerically, lexical order naturally reflects chronological introduction order, eliminating the need for manual sequence numbering or dependency graphs.

### What happens if a migration script fails during execution?

The `omarchy-migrate` runner executes scripts with `bash -euo pipefail` and aborts immediately upon any non-zero exit code. No marker file is created for failed migrations, ensuring they remain in the pending state and will be retried on the next execution attempt.

### Can I check for pending migrations without running them?

Yes. Running `omarchy-migrate --pending` performs a dry-run check that lists all unapplied migrations by comparing the source directory against marker files, without executing any scripts or modifying system state.