Migrations¶
When you update FM CLI itself, run fm migrate to upgrade your benches and infrastructure to match the new version.
Overview¶
FM migrations operate at two levels:
- FM Infrastructure — Global services (MariaDB, Redis, nginx-proxy) and CLI configuration
- Benches — Individual bench environments, configurations, and compose files
Migrations are version-aware: FM tracks which version each component is migrated to and only applies necessary upgrade steps.
Quick Start
After updating FM:
Always update CLI before migrating
Run fm self update first, then fm migrate. Running migrations on an old CLI version can cause compatibility issues.
How Migration Works¶
Migration Process¶
- Pre-flight checks — Validates current state and determines required migrations
- Backup creation — Creates backups of config files + MariaDB dump
- Apply migrations — Executes version-specific upgrade steps
- Verification — Validates successful migration
- Cleanup — Updates version tracking, removes old backups (optional)
What Gets Backed Up¶
| Component | Backup Location | Restoreable |
|---|---|---|
| Bench config files | ~/frappe/sites/<bench>/backups/migrations/<timestamp>/ |
✅ Yes |
| MariaDB database | Same as bench config | ✅ Yes (SQL dump) |
| Docker compose files | Same as bench config | ✅ Yes |
Global config (fm_config.toml) |
~/frappe/backups/migrations/<timestamp>/ |
✅ Yes |
Backup timestamp format
Backups use format: DD-Mon-YY--HH-MM-SS (e.g., 12-Apr-26--14-30-45)
Version Tracking¶
FM tracks migration state in two places:
Global infrastructure: ~/frappe/fm_config.toml
Per-bench: ~/frappe/sites/<benchname>/bench_config.toml
Migration Commands¶
Migrate Infrastructure Only¶
Applies only FM infrastructure migrations (global services, CLI config). Safe to run after every CLI update.
When to use:
- After running
fm self update - No benches need upgrading yet
- Just want to update global services
Migrate Specific Bench¶
Migrates a single bench to current FM version.
What happens:
- Backs up
bench_config.toml,docker-compose*.yml, MariaDB database - Applies bench-specific migration steps (SSL config format, compose changes, etc.)
- Updates
migration_state.migrated_toin bench config
Bench must be stopped first
Stop the bench before migrating:
Migrate All Benches¶
Migrates all benches in ~/frappe/sites/.
Confirmation prompt:
Found 5 benches requiring migration:
- mybench (v0.18.0 → v0.19.0)
- testbench (v0.18.0 → v0.19.0)
- prod (v0.18.0 → v0.19.0)
Proceed with migration? [y/n]:
Skip prompt:
Exclude Benches¶
Migrate all benches except specified ones (comma-separated).
Use for problematic benches
Exclude broken or archived benches from mass migrations, then handle them individually later.
Failure Handling¶
On-Failure Strategies¶
Control what happens when a bench migration fails:
--on-failure=prompt (default)¶
Asks what to do after each failure.
Interactive prompt:
Migration failed for 'mybench':
Error: SSL certificate format incompatible
[yes] Rollback bench to pre-migration state
[no] Skip rollback - Leave bench as-is (manual fix required)
Do you want to rollback the bench? [yes/no]:
--on-failure=rollback¶
Automatically rollback on failure (safest for single bench).
What happens:
- Migration fails
- Restores backups (config files, docker-compose files, MariaDB dump)
- Bench returns to pre-migration state
- Exit with error
Recommended for production benches
Use rollback for critical production benches to ensure they never end up in a half-migrated state.
--on-failure=archive¶
Move failed benches to archive, continue migrating others (partial success OK).
What happens:
- Migration fails for
mybench - Moves
~/frappe/sites/mybench/→~/frappe/archived-sites/mybench/ - Continues migrating remaining benches
- Prints summary of archived benches at end
Only for --all-benches
Archive mode requires --all-benches (not supported for single bench migrations).
Use case: Large bench fleets where some failures are acceptable, and you'll investigate archived benches later.
Backup Management¶
Skip All Backups (Dangerous)¶
Use only in controlled scenarios
Skipping backups means no rollback possible if migration fails. Only use when:
- You have external backups
- Backup creation itself is failing (disk space, permissions)
- Testing in disposable dev environments
Skip Backups for Specific Benches¶
Skip backups for specified benches (comma-separated), still back up others.
Use case: Dev benches with large databases where backup time is prohibitive.
Backup Restoration¶
Manual Rollback¶
If you need to manually restore a bench from backup:
# Find backup timestamp
ls ~/frappe/sites/mybench/backups/migrations/
# Example: 12-Apr-26--14-30-45
BACKUP_TS="12-Apr-26--14-30-45"
# Stop bench
fm stop mybench
# Restore config files
cp ~/frappe/sites/mybench/backups/migrations/$BACKUP_TS/bench_config.toml \
~/frappe/sites/mybench/
# Restore database (requires bench running)
fm start mybench
fm shell mybench -c "bench restore ~/workspace/frappe-bench/sites/backups/migrations/$BACKUP_TS/database.sql.gz"
Database backups are gzipped SQL dumps
Use bench restore command inside the bench to restore database from .sql.gz file.
Version-Specific Migration Notes¶
v0.19.0 Notable Changes¶
Toolchain changes:
- Switched from
pyenv+nvmtouv+fnmfor Python/Node version management - Python/Node versions now auto-detected from app
pyproject.toml
SSL configuration changes:
- Multi-certificate support (individual certs per domain)
- New
ssl_certificatesarray format inbench_config.toml - Old single-certificate configs automatically converted
Migration impact:
- Requires bench container rebuild (Python/Node toolchain replacement)
- SSL config files regenerated in new format
- Approximately 2-5 minutes per bench (depending on app count)
Troubleshooting¶
Migration Fails with Backup Error¶
Symptom: Error creating backup: Disk quota exceeded
Solution:
# Check disk space
df -h ~/frappe
# Clean old backups
rm -rf ~/frappe/backups/migrations/<old-timestamp>/
# Or skip backups (if safe)
fm migrate mybench --skip-all-backup
Bench Stuck in Half-Migrated State¶
Symptom: Migration failed, bench won't start, rollback wasn't triggered
Solution:
# Find most recent backup
ls ~/frappe/sites/mybench/backups/migrations/ | sort -r | head -1
# Manually restore (see "Manual Rollback" above)
Migration Says "Already Up to Date" But Bench Broken¶
Symptom: fm migrate mybench says already migrated, but bench config is wrong
Solution:
Reset migration state to force re-migration:
# Edit bench_config.toml
nano ~/frappe/sites/mybench/bench_config.toml
# Remove or change [migration_state] section:
[migration_state]
migrated_to = "0.18.0" # Set to previous version
# Save and re-run migration
fm migrate mybench
Migration Internals¶
Migration Discovery¶
FM automatically discovers and applies migrations by comparing:
- Current FM CLI version (from
fm --version) - Infrastructure migration state (from
fm_config.toml) - Each bench migration state (from
bench_config.toml)
Migration selection:
- If CLI = 0.19.0, infrastructure = 0.18.0 → Apply 0.19.0 infrastructure migration
- If CLI = 0.19.0, bench = 0.18.0 → Apply 0.19.0 bench migration
- If CLI = 0.19.0, bench = 0.19.0 → Skip (already migrated)
Migration Execution Order¶
- Infrastructure migrations (always first)
- Global database schema upgrades
- Global service config changes
-
CLI config format updates
-
Bench migrations (one bench at a time)
- Bench config format changes
- Docker compose file updates
- SSL certificate format conversions
- Per-bench database migrations (if needed)
Sequential execution
Benches are migrated sequentially (not parallel) to avoid database lock conflicts and ensure proper error handling.
See also: Configuration reference, Architecture reference