Overview
SwiftData (iOS 17+) is Core Data with a Swift-native surface: @Model replaces the data model editor, @Query replaces @FetchRequest, and automatic migrations handle additive schema changes. Core Data is the battle-tested stack with migration tooling, CloudKit configuration knobs, and derived attributes that SwiftData does not yet match. Neither is universally superior; the right choice depends on deployment target, schema complexity, and whether the codebase already ships a store. This page is a companion to core-data and core-data-stack.
Use SwiftData for new apps targeting iOS 17+ with simple schemas
SwiftData removes boilerplate. A model that would take an .xcdatamodeld file, a generated subclass, and a context setup becomes three lines.
import SwiftData
@Model
final class Item {
var title: String
var createdAt: Date
var isArchived: Bool = false
init(title: String) {
self.title = title
self.createdAt = Date()
}
}Additive schema changes (new attribute, new model) migrate automatically. @Query in a view reacts to changes without a context injection. The gain in code clarity is substantial on greenfield apps.
Stay on Core Data when you ship an existing store
Migrating a live Core Data store to SwiftData is not trivial. The stores use the same SQLite file format, and SwiftData can read a Core Data store, but the migration path requires care: attribute naming conventions differ, and any custom NSEntityMigrationPolicy has no SwiftData equivalent. For existing apps, the cost of migration rarely pays off until a major rewrite.
Stay on Core Data when the schema uses features SwiftData does not support
As of iOS 18, SwiftData does not support:
- Fetched properties (computed cross-entity lookups).
- Derived attributes (aggregate values stored at save time).
- Ordered relationships backed by
NSOrderedSet. NSFetchedResultsControllerwith section name key paths for UIKit table views.- Custom
NSEntityMigrationPolicyfor complex multi-version data transforms.
If any of these are on the roadmap, stay on Core Data.
Use Core Data for NSPersistentCloudKitContainer with fine-grained CloudKit control
NSPersistentCloudKitContainer lets you configure record zones, sharing, and sync conflict policies directly. SwiftData has CloudKit sync support, but the configuration surface is smaller. For apps that rely on CloudKit sharing (share a list with another user, conflict resolution), Core Data’s container is more capable today.
Coexist using a shared SQLite store during incremental migration
SwiftData and Core Data can share the same SQLite file. This allows you to migrate one entity or subsystem at a time rather than all at once.
let storeURL = PersistenceController.shared.container.persistentStoreDescriptions
.first!.url!
let config = ModelConfiguration(url: storeURL)
let container = try ModelContainer(
for: Item.self, NewEntity.self,
configurations: config
)Test the shared store approach thoroughly. Both frameworks write to the same file; conflicts arise when both write the same row in the same transaction.
Abstract persistence behind a protocol to stay framework-agnostic
If you are uncertain about the long-term choice, wrap persistence in a protocol from day one. Both a Core Data implementation and a SwiftData implementation satisfy the same interface; you swap one for the other without touching view code. See core-data-stack for the repository pattern.
protocol NoteRepository {
func notes() throws -> [Note]
func add(title: String, body: String) throws
func delete(id: UUID) throws
}Concrete types CoreDataNoteRepository and SwiftDataNoteRepository implement the protocol independently. The swiftui view layer receives the protocol type.
Prefer SwiftData for Swift 6 strict concurrency compliance
SwiftData’s @Model objects are Sendable under the actor model; NSManagedObject is not. In a Swift 6 codebase with strict concurrency checking, passing NSManagedObject across actor boundaries requires unsafe annotations or careful NSManagedObjectID plumbing. For teams adopting Swift 6 on new code, SwiftData is easier to keep warning-free. See core-data-concurrency for the Core Data patterns that mitigate this.