For a more detailed introduction to Monarch, check out my blog post introducing Monarch.
You don’t always get it right the first time. That’s why pencils have erasers — and why apps have migrations.
-
Simple Migrations: Define independent migrations without worrying about state management, making it easy to evolve your app over time.
-
Built for Swift and SwiftUI: Monarch’s migrations feel right at home in any Swift app, with a clean SwiftUI API.
-
Dependency Injection: Whether your migration is simple or complex, Monarch’s easy-to-use dependency injection provides structure to prevent data-related issues.
Setting up migrations in your app is simple:
- Define your migrations using the
Migration
protocol. - Add your migrations to a
MigrationGroup
. - Run your migrations using the
runMigrations
view modifier.
// 1. Define a migration
struct MigrateUserDataToAppGroup: Migration {
@MigrationDependency private var userDefaultsAppState
@MigrationDependency private var sharedAppState
static let id: MigrationID = "MigrateUserDataToAppGroup"
func run() async throws {
// Migrate the user data from UserDefaults to an app group, so you can share data across targets
sharedAppState.userData = userDefaultsAppState.userData
userDefaultsAppState.userData = nil
}
}
// 2. Group your migrations and add dependencies
let migrations = MigrationGroup {
MigrateUserDataToAppGroup()
// Add more migrations here
}
.migrationDependency(self.userDefaultsAppState)
.migrationDependency(self.sharedAppState)
// 3. Run migrations in your SwiftUI app
struct ContentView: View {
var body: some View {
Text("Hello, Monarch! 🦋")
.runMigrations {
migrations
}
}
}
That’s all you need to get started with Monarch! Add as many migrations and dependencies as needed to help evolve your app over time.
Monarch offers various ways to customize and control your migration process:
If the timing of migrations is crucial in your app, you can use the MigrationRunner
for full control. Here’s an example of an app that leverages Monarch’s functionality to manually run migrations:
struct ButterflyTrackerApp: App {
@State var appState = AppState()
@State var preferences = Preferences()
var body: some Scene {
WindowGroup {
ContentView()
.task {
try await self.runMigrations()
}
}
}
func runMigrations() async throws {
MigrationRunner.removeAllMigrations()
MigrationRunner.markMigrationAsCompleted(withID: ResetButterflyListMigration.id)
let migrationGroup = MigrationGroup {
ProvideButterlyFansPremiumAccountAccessMigration()
RemoveAccidentallyAddedMothMigration()
}
.migrationDependency(self.appState)
.migrationDependency(self.preferences)
try await MigrationRunner.runMigrations({ migrationGroup })
}
}
// Run the migrations in a MigrationGroup.
public static func runMigrations(_ migrationGroup: MigrationGroup) async throws
// Mark a migration as completed, without actually running it. This is useful when transitioning to Monarch from another migration system.
public static func markMigrationAsCompleted(withID id: MigrationID)
// Remove a specific migration that has previously run, allowing it to be re-run.
public static func removeMigration(withID id: MigrationID)
// Remove all previously run migrations.
public static func removeAllMigrations()
Note
Monarch stores its list of completed migrations in UserDefaults, which can take up to 7 seconds to synchronize. If the user re-runs these migrations within this 7-second window, such as by relaunching the app, migrations may be re-run.
- iOS 17.0+
- macOS 14.0+
- Xcode 14+
- Swift 5.10+
Add Monarch as a dependency in your Package.swift
file:
dependencies: [
.package(url: "https://github.com/yourusername/Monarch.git", .upToNextMajor(from: "1.0.0"))
]
Then, add Monarch to your target dependencies:
targets: [
.target(
name: "YourTarget",
dependencies: ["Monarch"]
)
]
If you prefer not to use SPM, you can integrate Monarch into your project manually by copying the files from the Sources/Monarch
directory.
Hi, I'm Joe everywhere on the web, but especially on Threads.
See the license for more information about how you can use Monarch.
Monarch is a labor of love to help developers build better apps, making it easier for you to unlock your creativity and make something amazing for your yourself and your users. If you find Monarch valuable I would really appreciate it if you'd consider helping sponsor my open source work, so I can continue to work on projects like Monarch to help developers like yourself.