WhollySoftware
Back to blogMobile

SwiftData vs Core Data: Migrating a Production App

Wholly Software TeamSeptember 19, 20257 min read
SwiftData vs Core Data: Migrating a Production App

A client's five-year-old journaling app had a Core Data stack with a moderately complex schema — entries, tags, attachments, and a many-to-many relationship between entries and tags — and wanted to move to SwiftData both to simplify the codebase and to unblock a broader SwiftUI rewrite. We treated this as a real migration project with a rollback plan, not a quick framework swap, because Core Data migrations that go wrong can corrupt user data silently.

SwiftData's @Model macro made the day-to-day model code substantially shorter — the entry and tag models went from roughly 90 lines of NSManagedObject subclass boilerplate to about 25 lines of SwiftData model code. For straightforward one-to-many relationships (entry to attachments) this was close to a drop-in replacement conceptually, and query code using #Predicate read more naturally than NSPredicate's string-based or NSExpression-based approach.

The many-to-many entry-tag relationship was where we hit real friction. SwiftData's relationship inference didn't handle the inverse relationship on this many-to-many case the way we expected out of the box in the SDK version we shipped with, occasionally leaving orphaned tag references after a delete. We ended up making tag deletion explicit — walking the relationship and clearing it manually before delete — rather than relying on SwiftData's cascade behavior, which was more conservative than what we'd had working reliably in Core Data.

Migrating existing user data was the part we spent the most testing time on. We didn't do a big-bang schema swap; instead we kept the existing Core Data SQLite store as the source of truth, wrote a one-time migration routine that reads through Core Data's NSManagedObjectContext and writes into a new SwiftData store, and ran it behind a feature flag on a subset of TestFlight users first. We also kept a Core Data fallback path in the app for one release cycle in case SwiftData surfaced a data-loss issue post-launch, which it didn't, but the safety net was worth the extra week of work.

Overall we'd recommend the migration for apps with straightforward relationship models, but for anything with complex many-to-many relationships or heavy NSFetchedResultsController usage tied to existing UIKit table views, we'd budget real testing time specifically around relationship integrity — that's the area where SwiftData's abstractions are newest and least battle-tested compared to Core Data's fifteen-plus years in production.

iOSSwiftDataCore DataData Migration
SwiftData vs Core Data: Migrating a Production App — Wholly Software