@Model is the schema. ModelContext is the unit of work. UI: swiftui-development. Language: swift. Tests: swift-testing.
Preserve legacy Core Data; do not migrate "in passing". CloudKit only if the product requires sync.
Stack and scope
| Ask | Role |
|---|---|
| SwiftData | Models, container, query |
| SwiftUI | @Query, .modelContainer |
| CloudKit | Optional sync (cloudKitDatabase) |
Organization
Models/
Order.swift # @Model
Persistence/
PersistenceStack.swift # ModelContainer
- Models without network logic. Services use
ModelContextinjected. - One container per app (or per explicit store: in-memory in tests).
Non-negotiable rules
ModelContainercreated once; inject context — do not instantiate a store in each View.- Writes in the correct isolation (
MainActorif the UI observes; background context for heavy import). try context.save()with handled error. Do not ignore.- Explicit relationships (
@Relationshipdelete rules). Avoid cycles without inverses. - Predicates (
#Predicate) — no filtering gigantic arrays in the View. - Tests with
isStoredInMemoryOnly: true.
@Model
final class Order {
var id: UUID
var createdAt: Date
@Relationship(deleteRule: .cascade)
var items: [OrderItem]
}
SwiftUI
.modelContainer(stack.container)at the root.@Querywithfilter/sortstable.animationaware.- Do not do
try! modelContext.fetchin thebody. - Edits: mute the
@Modelandsavein the intent (button /onDisappeardocumented).
Concurrency
ModelActor(or the deployment default) for off-main work.- Do not pass
ModelContextbetween actors. Pass IDsPersistentIdentifierand refetch. - Batch import: background context + periodic save.
Schema and migration
- Property change = versioning. Lightweight when the runtime allows it; versioned schema for breaking.
- User data is not disposable. No store reset in prod.
- Defaults on new properties.
CloudKit (if enabled)
- CloudKit-friendly types (no fragile custom unique).
- Conflicts: documented merge policy.
- Development: team iCloud container; do not hardcode another environment.
Anti-patterns
@Querywithout sort in a list the user reordersModelContextglobal static- Fetch in
body - SwiftData for a simple settings blob —
AppStorage/ equivalent DataStore - Migrate Core Data in the middle of a screen
Integration with other skills
- Swift:
swift - UI:
swiftui-development - Widgets reading data:
widgetkit(App Group / shared store if needed) - MVVM:
mvvm-architecture
Completion criteria
- Single container; save with handled error
- Queries via
@Query/ FetchDescriptor, not manual scan - Isolation/IDs between threads
- In-memory tests of the persistence path
- No destructive reset in prod