Skip to content

SQLiteData Migration ​

Complete migration guide from Apple's SwiftData to Point-Free's SQLiteData, covering when to migrate, pattern equivalents, and gradual migration strategies.

Overview ​

Guide for migrating from SwiftData to SQLiteData, including decision framework, code pattern conversions, CloudKit sharing (SwiftData can't), and performance considerations.

When to Migrate ​

Migrate to SQLiteData When ​

  • ✅ Need CloudKit record sharing (SwiftData only syncs, no sharing)
  • ✅ Have 50k+ records with performance concerns
  • ✅ Want value types (structs) over reference types (classes)
  • ✅ Need more control over SQL queries
  • ✅ Prefer explicit over magic behavior

Stay with SwiftData When ​

  • Simple CRUD with native Apple integration
  • Already working well with @Model classes
  • Don't need CloudKit record sharing
  • Team prefers Apple-native solutions

Pattern Equivalents ​

Model Definition ​

SwiftData

swift
@Model
class Task {
    var id: UUID
    var title: String
    var isComplete: Bool

    init(title: String) {
        self.id = UUID()
        self.title = title
        self.isComplete = false
    }
}

SQLiteData

swift
@Table
struct Task: Identifiable, Sendable {
    @Attribute(.primaryKey)
    var id: UUID
    var title: String
    var isComplete: Bool
}

Queries ​

SwiftData

swift
@Query(filter: #Predicate { !$0.isComplete })
var incompleteTasks: [Task]

SQLiteData

swift
@FetchAll(Task.where { !$0.isComplete })
var incompleteTasks: [Task]

Relationships ​

SwiftData

swift
@Model
class Task {
    @Relationship(deleteRule: .cascade)
    var subtasks: [Subtask]
}

SQLiteData

swift
@Table
struct Task: Identifiable, Sendable {
    var id: UUID
    // Relationships via foreign keys
}

@Table
struct Subtask: Identifiable, Sendable {
    var id: UUID
    var taskId: UUID  // Foreign key
}

Migration Strategy ​

Gradual Migration ​

  1. Add SQLiteData alongside SwiftData
  2. Migrate one model at a time
  3. Keep both running during transition
  4. Remove SwiftData when complete

Data Migration ​

swift
func migrateToSQLiteData() async throws {
    // Fetch from SwiftData
    let tasks = try modelContext.fetch(FetchDescriptor<Task>())

    // Write to SQLiteData
    try await database.write { db in
        for task in tasks {
            try SQLiteTask.insert {
                SQLiteTask(
                    id: task.id,
                    title: task.title,
                    isComplete: task.isComplete
                )
            }.execute(db)
        }
    }
}

CloudKit Sharing ​

SwiftData limitation: Can only sync, cannot share records

SQLiteData advantage:

swift
// Full CloudKit sharing support
let share = CKShare(rootRecord: record)
try await database.share(record, with: share)

Performance Comparison ​

OperationSwiftDataSQLiteData
Insert 50k~60s~30s
Fetch 10k~2s~0.5s
Complex queryCore Data layerDirect SQL

Released under the MIT License